Index: vm/include/jit_intf.h =================================================================== --- vm/include/jit_intf.h (revision 585455) +++ vm/include/jit_intf.h (working copy) @@ -207,6 +207,9 @@ VMEXPORT Field_Handle class_get_field(Class_Handle ch, unsigned idx); VMEXPORT int class_get_super_offset(); +VMEXPORT Field_Handle class_get_field_by_name(Class_Handle ch, const char* name); +VMEXPORT Method_Handle class_get_method_by_name(Class_Handle ch, const char* name); + VMEXPORT int class_get_depth(Class_Handle cl); //#endif //:: Index: vm/port/src/encoder/ia32_em64t/enc_tabl.cpp =================================================================== --- vm/port/src/encoder/ia32_em64t/enc_tabl.cpp (revision 584779) +++ vm/port/src/encoder/ia32_em64t/enc_tabl.cpp (working copy) @@ -436,7 +436,6 @@ END_OPCODES() END_MNEMONIC() - #undef DEFINE_ALU_OPCODES // // @@ -1409,7 +1408,7 @@ END_MNEMONIC() /* -MOVS is a special case. +MOVS and CMPS are the special cases. Most the code in both CG and Encoder do not expect 2 memory operands. Also, they are not supposed to setup constrains on which register the memory reference must reside - m8,m8 or m32,m32 is not the choice. @@ -1438,7 +1437,28 @@ END_OPCODES() END_MNEMONIC() +BEGIN_MNEMONIC(CMPSB, MF_AFFECTS_FLAGS, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {0xA6}, {r32,r32,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {0xA6}, {r64,r64,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() +BEGIN_MNEMONIC(CMPSW, MF_AFFECTS_FLAGS, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {Size16, 0xA7}, {r32,r32,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {Size16, 0xA7}, {r64,r64,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMPSD, MF_AFFECTS_FLAGS, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {0xA7}, {r32,r32,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {0xA7}, {r64,r64,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + + BEGIN_MNEMONIC(WAIT, MF_AFFECTS_FLAGS, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x9B}, {}, N }, Index: vm/port/src/encoder/ia32_em64t/enc_defs.h =================================================================== --- vm/port/src/encoder/ia32_em64t/enc_defs.h (revision 584779) +++ vm/port/src/encoder/ia32_em64t/enc_defs.h (working copy) @@ -428,6 +428,9 @@ Mnemonic_CMP, // Compare Two Operands Mnemonic_CMPXCHG, // Compare and exchange Mnemonic_CMPXCHG8B, // Compare and Exchange 8 Bytes +Mnemonic_CMPSB, // Compare Two Bytes at DS:ESI and ES:EDI +Mnemonic_CMPSW, // Compare Two Words at DS:ESI and ES:EDI +Mnemonic_CMPSD, // Compare Two Doublewords at DS:ESI and ES:EDI // // double -> float Mnemonic_CVTSD2SS, // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value Index: vm/vmcore/src/class_support/C_Interface.cpp =================================================================== --- vm/vmcore/src/class_support/C_Interface.cpp (revision 584779) +++ vm/vmcore/src/class_support/C_Interface.cpp (working copy) @@ -1780,6 +1780,30 @@ return ch->get_field(idx); } // class_get_field +Method_Handle class_get_method_by_name(Class_Handle ch, const char* name) +{ + assert(ch); + for(int idx = 0; idx < ch->get_number_of_methods(); idx++) { + Method_Handle meth = ch->get_method(idx); + if(strcmp(meth->get_name()->bytes, name) == 0) { + return meth; + } + } + return NULL; +} // class_get_method_by_name + +Field_Handle class_get_field_by_name(Class_Handle ch, const char* name) +{ + assert(ch); + for(int idx = 0; idx < ch->get_number_of_fields(); idx++) { + Field_Handle fld = ch->get_field(idx); + if(strcmp(fld->get_name()->bytes, name) == 0) { + return fld; + } + } + return NULL; +} // class_get_field_by_name + Field_Handle class_get_instance_field(Class_Handle ch, unsigned idx) { assert(ch); Index: vm/jitrino/config/ia32/server_static.emconf =================================================================== --- vm/jitrino/config/ia32/server_static.emconf (revision 584779) +++ vm/jitrino/config/ia32/server_static.emconf (working copy) @@ -24,7 +24,7 @@ -XX:jit.SS_OPT.path=opt_init,lock_method,translator,optimizer,hir2lir,codegen,unlock_method --XX:jit.SS_OPT.path.optimizer=ssa,simplify,dce,uce,statprof,devirt,inline,purge,simplify,dce,uce,lazyexc,throwopt,statprof,hvn,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,unroll,ssa,simplify,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,classic_abcd,dce,uce,gcm,dessa,statprof +-XX:jit.SS_OPT.path.optimizer=ssa,simplify,dce,uce,statprof,devirt,hlo_api_magic,inline,purge,simplify,dce,uce,lazyexc,throwopt,statprof,hvn,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,unroll,ssa,simplify,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,classic_abcd,dce,uce,gcm,dessa,statprof -XX:jit.SS_OPT.path.codegen=bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info -XX:jit.SS_OPT.path.dce1=cg_dce -XX:jit.SS_OPT.path.dce2=cg_dce @@ -34,7 +34,7 @@ #inliner configuration -XX:jit.SS_OPT.SS_OPT_inliner_pipeline.filter=- --XX:jit.SS_OPT.SS_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,statprof,devirt +-XX:jit.SS_OPT.SS_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,statprof,devirt,hlo_api_magic -XX:jit.SS_OPT.arg.optimizer.inline.pipeline=SS_OPT_inliner_pipeline -XX:jit.SS_OPT.arg.codegen.dce1.early=yes Index: vm/jitrino/config/ia32/client.emconf =================================================================== --- vm/jitrino/config/ia32/client.emconf (revision 584779) +++ vm/jitrino/config/ia32/client.emconf (working copy) @@ -53,7 +53,7 @@ -XX:jit.CD_OPT.path=opt_init,lock_method,translator,optimizer,hir2lir,codegen,unlock_method --XX:jit.CD_OPT.path.optimizer=ssa,devirt,inline,purge,simplify,dce,uce,lazyexc,throwopt,memopt,simplify,dce,uce,lower,statprof,unroll,ssa,simplify,dce,uce,dessa,statprof +-XX:jit.CD_OPT.path.optimizer=ssa,devirt,hlo_api_magic,inline,purge,simplify,dce,uce,lazyexc,throwopt,memopt,simplify,dce,uce,lower,statprof,unroll,ssa,simplify,dce,uce,dessa,statprof -XX:jit.CD_OPT.path.codegen=bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info -XX:jit.CD_OPT.path.dce1=cg_dce -XX:jit.CD_OPT.path.dce2=cg_dce @@ -63,7 +63,7 @@ #inliner configuration -XX:jit.CD_OPT.CD_OPT_inliner_pipeline.filter=- --XX:jit.CD_OPT.CD_OPT_inliner_pipeline.path=ssa,devirt +-XX:jit.CD_OPT.CD_OPT_inliner_pipeline.path=ssa,devirt,hlo_api_magic -XX:jit.CD_OPT.arg.optimizer.inline.pipeline=CD_OPT_inliner_pipeline -XX:jit.CD_OPT.arg.codegen.dce1.early=yes Index: vm/jitrino/config/ia32/opt.emconf =================================================================== --- vm/jitrino/config/ia32/opt.emconf (revision 584779) +++ vm/jitrino/config/ia32/opt.emconf (working copy) @@ -24,7 +24,7 @@ -XX:jit.CS_OPT.path=opt_init,lock_method,translator,optimizer,hir2lir,codegen,unlock_method --XX:jit.CS_OPT.path.optimizer=ssa,devirt,inline,purge,simplify,dce,uce,lazyexc,throwopt,escape,dce,uce,memopt,simplify,dce,uce,lower,statprof,unroll,ssa,simplify,dce,uce,dessa,statprof +-XX:jit.CS_OPT.path.optimizer=ssa,devirt,hlo_api_magic,inline,purge,simplify,dce,uce,lazyexc,throwopt,escape,dce,uce,memopt,simplify,dce,uce,lower,statprof,unroll,ssa,simplify,dce,uce,dessa,statprof -XX:jit.CS_OPT.path.codegen=bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info -XX:jit.CS_OPT.path.dce1=cg_dce -XX:jit.CS_OPT.path.dce2=cg_dce @@ -34,7 +34,7 @@ #inliner configuration -XX:jit.CS_OPT.CS_OPT_inliner_pipeline.filter=- --XX:jit.CS_OPT.CS_OPT_inliner_pipeline.path=ssa,devirt +-XX:jit.CS_OPT.CS_OPT_inliner_pipeline.path=ssa,devirt,hlo_api_magic -XX:jit.CS_OPT.arg.optimizer.inline.pipeline=CS_OPT_inliner_pipeline Index: vm/jitrino/config/ia32/server.emconf =================================================================== --- vm/jitrino/config/ia32/server.emconf (revision 584779) +++ vm/jitrino/config/ia32/server.emconf (working copy) @@ -71,7 +71,7 @@ -XX:jit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen --XX:jit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,purge,simplify,dce,uce,lazyexc,throwopt,so2-,simplify,dce,uce,escape,inline_helpers,purge,simplify,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,statprof,unroll,ssa,simplify,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,classic_abcd,dce,uce,gcm,dessa,fastArrayFill,statprof,markglobals +-XX:jit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,hlo_api_magic,inline,purge,simplify,dce,uce,lazyexc,throwopt,so2-,simplify,dce,uce,escape,inline_helpers,purge,simplify,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,statprof,unroll,ssa,simplify,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,classic_abcd,dce,uce,gcm,dessa,fastArrayFill,statprof,markglobals -XX:jit.SD2_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method -XX:jit.SD2_OPT.path.dce1=cg_dce -XX:jit.SD2_OPT.path.dce2=cg_dce @@ -85,7 +85,7 @@ #inliner configuration -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.filter=- --XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf +-XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,hlo_api_magic -XX:jit.SD2_OPT.arg.optimizer.inline.pipeline=SD2_OPT_inliner_pipeline -XX:jit.SD2_OPT.arg.optimizer.inline.connect_early=false #devirt configuration for inliner pipeline Index: vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp (revision 584779) +++ vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp (working copy) @@ -513,7 +513,10 @@ if (inst->hasKind(Inst::Kind_ControlTransferInst) || inst->getMnemonic() == Mnemonic_MOVS8 || inst->getMnemonic() == Mnemonic_MOVS16 || - inst->getMnemonic() == Mnemonic_MOVS32 ) { + inst->getMnemonic() == Mnemonic_MOVS32 || + inst->getMnemonic() == Mnemonic_CMPSB || + inst->getMnemonic() == Mnemonic_CMPSW || + inst->getMnemonic() == Mnemonic_CMPSD ) { //Do nothing, calls return only bases } else { Opnd* fromOpnd = NULL; @@ -532,9 +535,7 @@ fromOpnd = inst->getOpnd(useIndex1); break; case Mnemonic_ADD: { -#ifdef _EM64T_ case Mnemonic_SUB: -#endif fromOpnd = opnd; Opnd* offsetOpnd = inst->getOpnd(useIndex1); Opnd* immOffset = findImmediateSource(offsetOpnd); Index: vm/jitrino/src/codegenerator/ia32/Ia32APIMagics.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32APIMagics.cpp (revision 584779) +++ vm/jitrino/src/codegenerator/ia32/Ia32APIMagics.cpp (working copy) @@ -60,6 +60,8 @@ virtual void run()=0; protected: + Opnd* addElemIndexWithLEA(Opnd* array, Opnd* index, Node* node); + IRManager* irm; CallInst* callInst; MethodDesc* md; @@ -79,6 +81,8 @@ DECLARE_HELPER_INLINER(Integer_numberOfTrailingZeros_Handler_x_I_x_I); DECLARE_HELPER_INLINER(Long_numberOfLeadingZeros_Handler_x_J_x_I); DECLARE_HELPER_INLINER(Long_numberOfTrailingZeros_Handler_x_J_x_I); +DECLARE_HELPER_INLINER(String_compareTo_Handler_x_String_x_I); +DECLARE_HELPER_INLINER(String_regionMatches_Handler_x_I_x_String_x_I_x_I_x_Z); void APIMagicsHandlerSession::runImpl() { CompilationContext* cc = getCompilationContext(); @@ -92,34 +96,45 @@ Node* node = *it; if (node->isBlockNode()) { for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { - if (!inst->hasKind(Inst::Kind_CallInst) || !((CallInst*)inst)->isDirect()) { + if (!inst->hasKind(Inst::Kind_CallInst)) { continue; } - CallInst* callInst = (CallInst*)inst; - Opnd * targetOpnd=callInst->getOpnd(callInst->getTargetOpndIndex()); - assert(targetOpnd->isPlacedIn(OpndKind_Imm)); - Opnd::RuntimeInfo * ri=targetOpnd->getRuntimeInfo(); - if( !ri || ri->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) { - continue; - }; - MethodDesc * md = (MethodDesc*)ri->getValue(0); - const char* className = md->getParentType()->getName(); - const char* methodName = md->getName(); - const char* signature = md->getSignatureString(); - if (!strcmp(className, "java/lang/Integer")) { - if (!strcmp(methodName, "numberOfLeadingZeros") && !strcmp(signature, "(I)I")) { - handlers.push_back(new (tmpMM) Integer_numberOfLeadingZeros_Handler_x_I_x_I(irm, callInst, md)); - } else if (!strcmp(methodName, "numberOfTrailingZeros") && !strcmp(signature, "(I)I")) { - handlers.push_back(new (tmpMM) Integer_numberOfTrailingZeros_Handler_x_I_x_I(irm, callInst, md)); + if ( ((CallInst*)inst)->isDirect() ) { + CallInst* callInst = (CallInst*)inst; + Opnd * targetOpnd=callInst->getOpnd(callInst->getTargetOpndIndex()); + assert(targetOpnd->isPlacedIn(OpndKind_Imm)); + Opnd::RuntimeInfo * ri=targetOpnd->getRuntimeInfo(); + if( !ri ) { + continue; + }; + if( ri->getKind() == Opnd::RuntimeInfo::Kind_MethodDirectAddr ){ + MethodDesc * md = (MethodDesc*)ri->getValue(0); + const char* className = md->getParentType()->getName(); + const char* methodName = md->getName(); + const char* signature = md->getSignatureString(); + if (!strcmp(className, "java/lang/Integer")) { + if (!strcmp(methodName, "numberOfLeadingZeros") && !strcmp(signature, "(I)I")) { + handlers.push_back(new (tmpMM) Integer_numberOfLeadingZeros_Handler_x_I_x_I(irm, callInst, md)); + } else if (!strcmp(methodName, "numberOfTrailingZeros") && !strcmp(signature, "(I)I")) { + handlers.push_back(new (tmpMM) Integer_numberOfTrailingZeros_Handler_x_I_x_I(irm, callInst, md)); + } + } else if (!strcmp(className, "java/lang/Long")) { + if (!strcmp(methodName, "numberOfLeadingZeros") && !strcmp(signature, "(J)I")) { + handlers.push_back(new (tmpMM) Long_numberOfLeadingZeros_Handler_x_J_x_I(irm, callInst, md)); + } else if (!strcmp(methodName, "numberOfTrailingZeros") && !strcmp(signature, "(J)I")) { + handlers.push_back(new (tmpMM) Long_numberOfTrailingZeros_Handler_x_J_x_I(irm, callInst, md)); + } + } + } else if( ri->getKind() == Opnd::RuntimeInfo::Kind_InternalHelperAddress ) { + if( strcmp((char*)ri->getValue(0),"String_compareTo")==0 ) { + if(getBoolArg("String_compareTo_as_magic", true)) + handlers.push_back(new (tmpMM) String_compareTo_Handler_x_String_x_I(irm, callInst, NULL)); + } else if( strcmp((char*)ri->getValue(0),"String_regionMatches")==0 ) { + if(getBoolArg("String_regionMatches_as_magic", true)) + handlers.push_back(new (tmpMM) String_regionMatches_Handler_x_I_x_String_x_I_x_I_x_Z(irm, callInst, NULL)); + } } - } else if (!strcmp(className, "java/lang/Long")) { - if (!strcmp(methodName, "numberOfLeadingZeros") && !strcmp(signature, "(J)I")) { - handlers.push_back(new (tmpMM) Long_numberOfLeadingZeros_Handler_x_J_x_I(irm, callInst, md)); - } else if (!strcmp(methodName, "numberOfTrailingZeros") && !strcmp(signature, "(J)I")) { - handlers.push_back(new (tmpMM) Long_numberOfTrailingZeros_Handler_x_J_x_I(irm, callInst, md)); - } } - } } } @@ -296,5 +311,237 @@ #endif } +void String_compareTo_Handler_x_String_x_I::run() { + //mov ds:esi, this + //mov es:edi, src + //mov ecx, min(this.count, src.count) + //repne cmpw + //if ZF == 0 (one of strings is a prefix) + // return this.count - src.count + //else + // return [ds:esi-2] - [es:edi-2] + + Node* callInstNode = callInst->getNode(); + Node* nextNode = callInstNode->getUnconditionalEdgeTarget(); + assert(nextNode!=NULL); + cfg->removeEdge(callInstNode->getUnconditionalEdge()); + + // arguments of the call are already prepared by respective HLO pass + // they are not the strings but 'value' arrays + Opnd* thisArr = getCallSrc(callInst, 0); + Opnd* thisIdx = getCallSrc(callInst, 1); + Opnd* thisLen = getCallSrc(callInst, 2); + Opnd* trgtArr = getCallSrc(callInst, 3); + Opnd* trgtIdx = getCallSrc(callInst, 4); + Opnd* trgtLen = getCallSrc(callInst, 5); + Opnd* valForCounter = getCallSrc(callInst, 6); + Opnd* res = getCallDst(callInst); + +#ifdef _EM64T_ + RegName counterRegName = RegName_RCX; + RegName thisAddrRegName = RegName_RSI; + RegName trgtAddrRegName = RegName_RDI; + Type* counterType = irm->getTypeManager().getInt64Type(); +#else + RegName counterRegName = RegName_ECX; + RegName thisAddrRegName = RegName_ESI; + RegName trgtAddrRegName = RegName_EDI; + Type* counterType = irm->getTypeManager().getInt32Type(); +#endif + + Node* counterIsZeroNode = irm->getFlowGraph()->createBlockNode(); + // if counter is zero jump to counterIsZeroNode immediately + callInstNode->appendInst(irm->newInst(Mnemonic_TEST, valForCounter, valForCounter)); + BranchInst* br = irm->newBranchInst(Mnemonic_JZ, NULL, NULL); + callInstNode->appendInst(br); + Node* node = irm->getFlowGraph()->createBlockNode(); + br->setTrueTarget(counterIsZeroNode); + br->setFalseTarget(node); + irm->getFlowGraph()->addEdge(counterIsZeroNode, nextNode, 1); + irm->getFlowGraph()->addEdge(callInstNode, counterIsZeroNode, 0.05); + irm->getFlowGraph()->addEdge(callInstNode, node, 0.95); + + // prepare counter + Opnd* counter = irm->newRegOpnd(counterType,counterRegName); + node->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, counter, valForCounter)); + + // prepare this position + Opnd* thisAddr = addElemIndexWithLEA(thisArr,thisIdx,node); + Opnd* thisAddrReg = irm->newRegOpnd(thisAddr->getType(),thisAddrRegName); + node->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, thisAddrReg, thisAddr)); + + // prepare trgt position + Opnd* trgtAddr = addElemIndexWithLEA(trgtArr,trgtIdx,node); + Opnd* trgtAddrReg = irm->newRegOpnd(trgtAddr->getType(),trgtAddrRegName); + node->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, trgtAddrReg, trgtAddr)); + + Inst* compareInst = irm->newInst(Mnemonic_CMPSW,thisAddrReg,trgtAddrReg,counter); + compareInst->setPrefix(InstPrefix_REPZ); + node->appendInst(compareInst); + + // counter is 0 means the same as last comparison leaves zero at ZF + br = irm->newBranchInst(Mnemonic_JZ, NULL, NULL); + node->appendInst(br); + + Node* differentStringsNode = irm->getFlowGraph()->createBlockNode(); + br->setTrueTarget(counterIsZeroNode); + br->setFalseTarget(differentStringsNode); + irm->getFlowGraph()->addEdge(node, counterIsZeroNode, 0.5); + irm->getFlowGraph()->addEdge(node, differentStringsNode, 0.5); + irm->getFlowGraph()->addEdge(differentStringsNode, nextNode, 1); + + // counter is zero + counterIsZeroNode->appendInst(irm->newInstEx(Mnemonic_SUB, 1, res, thisLen, trgtLen)); + + // strings are different + Opnd* two = irm->newImmOpnd(counterType,2); + differentStringsNode->appendInst(irm->newInstEx(Mnemonic_SUB, 1, thisAddrReg, thisAddrReg, two)); + differentStringsNode->appendInst(irm->newInstEx(Mnemonic_SUB, 1, trgtAddrReg, trgtAddrReg, two)); + Type* charType = irm->getTypeManager().getCharType(); + Opnd* thisChar = irm->newMemOpnd(charType, thisAddrReg); + Opnd* trgtChar = irm->newMemOpnd(charType, trgtAddrReg); + Opnd* dst = irm->newOpnd(charType); + differentStringsNode->appendInst(irm->newInstEx(Mnemonic_SUB, 1, dst, thisChar, trgtChar)); + differentStringsNode->appendInst(irm->newInstEx(Mnemonic_MOVSX, 1, res, dst)); + + callInst->unlink(); +} + +void String_regionMatches_Handler_x_I_x_String_x_I_x_I_x_Z::run() { + //mov ds:esi, this + //mov es:edi, src + //mov ecx, counter + //repne cmpw + //if ZF == 0 (one of strings is a prefix) + // return this.count - src.count + //else + // return [ds:esi-2] - [es:edi-2] + + Node* node = callInst->getNode(); + Node* nextNode = NULL; + + if(callInst == node->getLastInst()) { + nextNode = node->getUnconditionalEdgeTarget(); + assert(nextNode!=NULL); + } else { + nextNode = irm->getFlowGraph()->splitNodeAtInstruction(callInst, true, true, NULL); + } + cfg->removeEdge(node->getUnconditionalEdge()); + + // arguments of the call are already prepared by respective HLO pass + // they are not the strings but 'value' arrays + Opnd* thisArr = getCallSrc(callInst, 0); + Opnd* thisIdx = getCallSrc(callInst, 1); + Opnd* trgtArr = getCallSrc(callInst, 2); + Opnd* trgtIdx = getCallSrc(callInst, 3); + Opnd* valForCounter = getCallSrc(callInst, 4); + Opnd* res = getCallDst(callInst); + +#ifdef _EM64T_ + RegName counterRegName = RegName_RCX; + RegName thisAddrRegName = RegName_RSI; + RegName trgtAddrRegName = RegName_RDI; + Type* counterType = irm->getTypeManager().getInt64Type(); +#else + RegName counterRegName = RegName_ECX; + RegName thisAddrRegName = RegName_ESI; + RegName trgtAddrRegName = RegName_EDI; + Type* counterType = irm->getTypeManager().getInt32Type(); +#endif + + // prepare counter + Opnd* counter = irm->newRegOpnd(counterType,counterRegName); + node->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, counter, valForCounter)); + + // prepare this position + Opnd* thisAddr = addElemIndexWithLEA(thisArr,thisIdx,node); + Opnd* thisAddrReg = irm->newRegOpnd(thisAddr->getType(),thisAddrRegName); + node->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, thisAddrReg, thisAddr)); + + // prepare trgt position + Opnd* trgtAddr = addElemIndexWithLEA(trgtArr,trgtIdx,node); + Opnd* trgtAddrReg = irm->newRegOpnd(trgtAddr->getType(),trgtAddrRegName); + node->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, trgtAddrReg, trgtAddr)); + + Inst* compareInst = irm->newInst(Mnemonic_CMPSW,thisAddrReg,trgtAddrReg,counter); + compareInst->setPrefix(InstPrefix_REPZ); + node->appendInst(compareInst); + + // counter is 0 means the same as last comparison leaves zero at ZF + BranchInst* br = irm->newBranchInst(Mnemonic_JZ, NULL, NULL); + node->appendInst(br); + + Node* sameRegionsNode = irm->getFlowGraph()->createBlockNode(); + Node* diffRegionsNode = irm->getFlowGraph()->createBlockNode(); + br->setTrueTarget(sameRegionsNode); + br->setFalseTarget(diffRegionsNode); + irm->getFlowGraph()->addEdge(node, sameRegionsNode, 0.5); + irm->getFlowGraph()->addEdge(sameRegionsNode, nextNode, 1); + irm->getFlowGraph()->addEdge(node, diffRegionsNode, 0.5); + irm->getFlowGraph()->addEdge(diffRegionsNode, nextNode, 1); + + // regions are equal + Opnd* one = irm->newImmOpnd(res->getType(),1); + sameRegionsNode->appendInst(irm->newInst(Mnemonic_MOV, res, one)); + + // regions are different + Opnd* zero = irm->newImmOpnd(res->getType(),0); + diffRegionsNode->appendInst(irm->newInst(Mnemonic_MOV, res, zero)); + + callInst->unlink(); +} + +// Compute address of the array element given +// address of the first element and index +// using 'LEA' instruction + +Opnd* APIMagicHandler::addElemIndexWithLEA(Opnd* array, Opnd* index, Node* node) +{ + ArrayType * arrayType=((Opnd*)array)->getType()->asArrayType(); + Type * elemType=arrayType->getElementType(); + Type * dstType=irm->getManagedPtrType(elemType); + + TypeManager& typeManager = irm->getTypeManager(); +#ifdef _EM64T_ + Type * indexType = typeManager.getInt64Type(); + Type * offType = typeManager.getInt64Type(); +#else + Type * indexType = typeManager.getInt32Type(); + Type * offType = typeManager.getInt32Type(); +#endif + + uint32 elemSize = 0; + if (elemType->isReference() + && Type::isCompressedReference(elemType->tag, irm->getCompilationInterface()) + && !elemType->isCompressedReference()) { + elemSize = 4; + } else { + elemSize = getByteSize(irm->getTypeSize(elemType)); + } + Opnd * elemSizeOpnd = irm->newImmOpnd(indexType, elemSize); + + Opnd * indexOpnd = index; + assert(index->getType() == indexType); //when this assertion fails 'convert' should be implemented +// indexOpnd = convert(indexOpnd, indexType); + + if ( indexOpnd->isPlacedIn(OpndKind_Imm) ) { + // we need to put index operand on a register to satisfy LEA constraint + int64 immValue = indexOpnd->getImmValue(); + if (immValue == 0) { + indexOpnd = NULL; + elemSizeOpnd = NULL; + } else { + Opnd * indexReg = irm->newOpnd(indexType); + node->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, indexReg, indexOpnd)); + indexOpnd = indexReg; + } + } + Opnd * arrOffset = irm->newImmOpnd(offType, arrayType->getArrayElemOffset()); + Opnd * addr = irm->newMemOpnd(dstType,(Opnd*)array, indexOpnd, elemSizeOpnd, arrOffset); + Opnd * dst = irm->newOpnd(dstType); + node->appendInst(irm->newInstEx(Mnemonic_LEA, 1, dst, addr)); + return dst; +} + }} //namespace Index: vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (revision 584779) +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (working copy) @@ -178,6 +178,8 @@ irManager.registerInternalHelperInfo("add_value_profile_value", IRManager::InternalHelperInfo((void*)&add_value_profile_value,&CallingConvention_STDCALL)); irManager.registerInternalHelperInfo("fill_array_with_const", IRManager::InternalHelperInfo((void*)&fill_array_with_const,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("String_compareTo", IRManager::InternalHelperInfo(NULL,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("String_regionMatches", IRManager::InternalHelperInfo(NULL,&CallingConvention_STDCALL)); } //_______________________________________________________________________________________________________________ @@ -2688,6 +2690,20 @@ appendInsts(irManager.newInternalRuntimeHelperCallInst("fill_array_with_const", numArgs, newArgs, dstOpnd)); break; } + case StringCompareTo: + { + assert(numArgs == 7); + Opnd * newArgs[7] = {(Opnd *)args[0], (Opnd *)args[1], (Opnd *)args[2], (Opnd *)args[3], (Opnd *)args[4], (Opnd *)args[5], (Opnd *)args[6]}; + appendInsts(irManager.newInternalRuntimeHelperCallInst("String_compareTo", numArgs, newArgs, dstOpnd)); + break; + } + case StringRegionMatches: + { + assert(numArgs == 5); + Opnd * newArgs[5] = {(Opnd *)args[0], (Opnd *)args[1], (Opnd *)args[2], (Opnd *)args[3], (Opnd *)args[4]}; + appendInsts(irManager.newInternalRuntimeHelperCallInst("String_regionMatches", numArgs, newArgs, dstOpnd)); + break; + } default: { assert(0); Index: vm/jitrino/src/codegenerator/CodeGenIntfc.h =================================================================== --- vm/jitrino/src/codegenerator/CodeGenIntfc.h (revision 584779) +++ vm/jitrino/src/codegenerator/CodeGenIntfc.h (working copy) @@ -169,7 +169,9 @@ SaveThisState, ReadThisState, LockedCompareAndExchange, - AddValueProfileValue + AddValueProfileValue, + StringCompareTo, + StringRegionMatches }; }; Index: vm/jitrino/src/optimizer/HLOAPIMagics.cpp =================================================================== --- vm/jitrino/src/optimizer/HLOAPIMagics.cpp (revision 0) +++ vm/jitrino/src/optimizer/HLOAPIMagics.cpp (revision 0) @@ -0,0 +1,470 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, George A. Timoshenko + */ + +#include "HLOAPIMagics.h" +#include "Opcode.h" +#include "PMF.h" +#include "VMInterface.h" + +namespace Jitrino { + +void +String_compareTo_HLO_Handler::run() +{ + IRManager* irm = builder->getIRManager(); + InstFactory& instFactory = builder->getInstFactory(); + ControlFlowGraph& cfg = builder->getControlFlowGraph(); + + Node* firstNode = callInst->getNode(); + Node* lastNode = cfg.splitNodeAtInstruction(callInst, true, true, instFactory.makeLabel()); + Node* dispatch = firstNode->getExceptionEdgeTarget(); + assert(dispatch); + callInst->unlink(); + cfg.removeEdge(firstNode->findEdge(true, lastNode)); + + builder->setCurrentBCOffset(callInst->getBCOffset()); + + // the fist two are tau operands + Opnd* dst = callInst->getDst(); + Opnd* thisStr = callInst->getSrc(2); + Opnd* trgtStr = callInst->getSrc(3); + + Class_Handle string = (Class_Handle)VMInterface::getSystemStringVMTypeHandle(); + FieldDesc* fieldCountDesc = irm->getCompilationInterface().getFieldByName(string,"count"); + assert(fieldCountDesc); + FieldDesc* fieldValueDesc = irm->getCompilationInterface().getFieldByName(string,"value"); + assert(fieldValueDesc); + // this field is optional + FieldDesc* offsetDesc = irm->getCompilationInterface().getFieldByName(string,"offset"); + Type* fieldType = fieldCountDesc->getFieldType(); + Type::Tag fieldTag = fieldType->tag; + + // gen at the end of first node + builder->setCurrentNode(firstNode); + Opnd *tauThisNullChecked = builder->genTauCheckNull(thisStr); + + // node + builder->genFallthroughNode(dispatch); + Opnd *tauThisInRange = builder->genTauHasType(thisStr, fieldCountDesc->getParentType()); + Opnd* thisLength = builder->genLdField(fieldCountDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd *tauTrgtNullChecked = builder->genTauCheckNull(trgtStr); + + // node + Node* branch = builder->genFallthroughNode(); + Opnd *tauTrgtInRange = builder->genTauHasType(trgtStr, fieldCountDesc->getParentType()); + Opnd* trgtLength = builder->genLdField(fieldCountDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + + LabelInst * ThisIsLonger = (LabelInst*)instFactory.makeLabel(); + builder->appendInst(instFactory.makeBranch(Cmp_GT,fieldTag,thisLength,trgtLength,ThisIsLonger)); + + VarOpnd* counterVar = builder->createVarOpnd(fieldType,false); + + // node (trgt is longer here) + builder->genFallthroughNode(); + SsaVarOpnd* thisLengthVar = builder->createSsaVarOpnd(counterVar); + builder->genStVar(thisLengthVar,thisLength); + builder->genEdgeFromCurrent(lastNode); // jump to merge + + // node (this is longer here) + builder->genNodeAfter(branch,ThisIsLonger); + SsaVarOpnd* trgtLengthVar = builder->createSsaVarOpnd(counterVar); + builder->genStVar(trgtLengthVar,trgtLength); + builder->genEdgeFromCurrent(lastNode); // jump to merge + + // last node (merge after counter definition) + builder->setCurrentNode(lastNode); + // gather counter value + Opnd* phiArgs[] = {thisLengthVar,trgtLengthVar}; + SsaVarOpnd* var = builder->createSsaVarOpnd(counterVar); + lastNode->appendInst(instFactory.makePhi(var,2,phiArgs)); + Opnd* counter = builder->createOpnd(fieldType); + lastNode->appendInst(instFactory.makeLdVar(counter,var)); + Opnd* thisStart = builder->genLdConstant(0); + Opnd* trgtStart = builder->genLdConstant(0); + if(offsetDesc) { + Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No); + Opnd* thisOffset = builder->genLdField(offsetDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* trgtOffset = builder->genLdField(offsetDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + thisStart = builder->genAdd(fieldType, mod, thisOffset, thisStart); + trgtStart = builder->genAdd(fieldType, mod, trgtOffset, trgtStart); + } + Opnd* thisValue = builder->genLdField(fieldValueDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* trgtValue = builder->genLdField(fieldValueDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + Opnd* opnds[] = {thisValue,thisStart,thisLength,trgtValue,trgtStart,trgtLength,counter}; + + // This helper call will be processed in Ia32ApiMagics pass + builder->appendInst(instFactory.makeJitHelperCall(dst, StringCompareTo, 7, opnds)); + + cfg.orderNodes(true); +} + +void +String_regionMatches_HLO_Handler::run() +{ + IRManager* irm = builder->getIRManager(); + InstFactory& instFactory = builder->getInstFactory(); + ControlFlowGraph& cfg = builder->getControlFlowGraph(); + + Node* firstNode = callInst->getNode(); + Node* lastNode = cfg.splitNodeAtInstruction(callInst, true, true, instFactory.makeLabel()); + Node* dispatch = firstNode->getExceptionEdgeTarget(); + assert(dispatch); + callInst->unlink(); + cfg.removeEdge(firstNode->findEdge(true, lastNode)); + + builder->setCurrentBCOffset(callInst->getBCOffset()); + + // the fist two are tau operands + Opnd* dst = callInst->getDst(); + Opnd* thisStr = callInst->getSrc(2); + Opnd* thisStart = callInst->getSrc(3); + Opnd* trgtStr = callInst->getSrc(4); + Opnd* trgtStart = callInst->getSrc(5); + Opnd* counter = callInst->getSrc(6); + + Class_Handle string = (Class_Handle)VMInterface::getSystemStringVMTypeHandle(); + FieldDesc* fieldCountDesc = irm->getCompilationInterface().getFieldByName(string,"count"); + assert(fieldCountDesc); + FieldDesc* fieldValueDesc = irm->getCompilationInterface().getFieldByName(string,"value"); + assert(fieldValueDesc); + // this field is optional + FieldDesc* offsetDesc = irm->getCompilationInterface().getFieldByName(string,"offset"); + + Type* fieldType = fieldCountDesc->getFieldType(); + Type::Tag fieldTag = fieldType->tag; + + // gen at the end of first node + builder->setCurrentNode(firstNode); + Opnd *tauThisNullChecked = builder->genTauCheckNull(thisStr); + + // node + builder->genFallthroughNode(dispatch); + Opnd *tauThisInRange = builder->genTauHasType(thisStr, fieldCountDesc->getParentType()); + Opnd *tauTrgtNullChecked = builder->genTauCheckNull(trgtStr); + + LabelInst * FalseResult = (LabelInst*)instFactory.makeLabel(); + Node* returnFalse = cfg.createBlockNode(FalseResult); + + // node + builder->genFallthroughNode(); + Opnd* zero = builder->genLdConstant(0); + Opnd *tauTrgtInRange = builder->genTauHasType(trgtStr, fieldCountDesc->getParentType()); + builder->appendInst(instFactory.makeBranch(Cmp_GT,fieldTag,zero,trgtStart,FalseResult)); + builder->genEdgeFromCurrent(returnFalse); + + // node + builder->genFallthroughNode(); + builder->appendInst(instFactory.makeBranch(Cmp_GT,fieldTag,zero,thisStart,FalseResult)); + builder->genEdgeFromCurrent(returnFalse); + + Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No); + + // node + builder->genFallthroughNode(); + Opnd* trgtLength = builder->genLdField(fieldCountDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + Opnd* trgtDiff = builder->genSub(fieldType, mod,trgtLength,trgtStart); + builder->appendInst(instFactory.makeBranch(Cmp_GT,fieldTag,counter,trgtDiff,FalseResult)); + builder->genEdgeFromCurrent(returnFalse); + + // node + builder->genFallthroughNode(); + Opnd* thisLength = builder->genLdField(fieldCountDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* thisDiff = builder->genSub(fieldType, mod,thisLength,thisStart); + builder->appendInst(instFactory.makeBranch(Cmp_GT,fieldTag,counter,thisDiff,FalseResult)); + builder->genEdgeFromCurrent(returnFalse); + + LabelInst * TrueResult = (LabelInst*)instFactory.makeLabel(); + Node* returnTrue = cfg.createBlockNode(TrueResult); + + // node + builder->genFallthroughNode(); + builder->appendInst(instFactory.makeBranch(Cmp_GTE,fieldTag,zero,counter,TrueResult)); + builder->genEdgeFromCurrent(returnTrue); + + // node + builder->genFallthroughNode(); + if(offsetDesc) { + Opnd* thisOffset = builder->genLdField(offsetDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* trgtOffset = builder->genLdField(offsetDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + thisStart = builder->genAdd(fieldType, mod, thisOffset, thisStart); + trgtStart = builder->genAdd(fieldType, mod, trgtOffset, trgtStart); + } + Opnd* thisValue = builder->genLdField(fieldValueDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* trgtValue = builder->genLdField(fieldValueDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + Opnd* opnds[] = {thisValue,thisStart,trgtValue,trgtStart,counter}; + + // This helper call will be processed in Ia32ApiMagics pass + VarOpnd* resultVar = builder->createVarOpnd(dst->getType(),false); + SsaVarOpnd* resVar = builder->createSsaVarOpnd(resultVar); + Opnd* res = builder->createOpnd(dst->getType()); + builder->appendInst(instFactory.makeJitHelperCall(res, StringRegionMatches, 5, opnds)); + builder->genStVar(resVar,res); + builder->genEdgeFromCurrent(lastNode); + + // returnFalse + builder->setCurrentNode(returnFalse); + Opnd* resFalse = builder->genLdConstant(0); + SsaVarOpnd* resFalseVar = builder->createSsaVarOpnd(resultVar); + builder->genStVar(resFalseVar,resFalse); + builder->genEdgeFromCurrent(lastNode); + + // returnTrue + builder->setCurrentNode(returnTrue); + Opnd* resTrue = builder->genLdConstant(1); + SsaVarOpnd* resTrueVar = builder->createSsaVarOpnd(resultVar); + builder->genStVar(resTrueVar,resTrue); + builder->genEdgeFromCurrent(lastNode); + + // lastNode + Opnd* phiArgs[] = {resVar,resFalseVar,resTrueVar}; + SsaVarOpnd* var = builder->createSsaVarOpnd(resultVar); + lastNode->appendInst(instFactory.makePhi(var,3,phiArgs)); + lastNode->appendInst(instFactory.makeLdVar(dst,var)); + + cfg.orderNodes(true); +} + +Node* +HLOAPIMagicIRBuilder::genNodeAfter(Node* srcNode, LabelInst* label, Node* dispatch) { + currentNode = cfg.createBlockNode(label); + cfg.addEdge(srcNode, currentNode); + if (dispatch != NULL) { + cfg.addEdge(currentNode, dispatch, 0.001); + } + return currentNode; +} + +Node* +HLOAPIMagicIRBuilder::genNodeAfterCurrent(LabelInst* label, Node* dispatch) { + return genNodeAfter(currentNode,label,dispatch); +} + +Node* +HLOAPIMagicIRBuilder::genFallthroughNode(Node* dispatch) { + return genNodeAfter(currentNode,instFactory.makeLabel(),dispatch); +} + +void +HLOAPIMagicIRBuilder::appendInst(Inst* inst) { + inst->setBCOffset(currentBCOffset); + currentNode->appendInst(inst); +} + +void +HLOAPIMagicIRBuilder::genCopy(Opnd* trgt, Opnd* src) { + appendInst(instFactory.makeCopy(trgt,src)); +} + +Opnd* +HLOAPIMagicIRBuilder::genLdField(FieldDesc* fieldDesc, Opnd* base, + Opnd* tauBaseNonNull, Opnd* tauAddressInRange) { + Type* fieldType = fieldDesc->getFieldType(); + assert(fieldType); + + Opnd* fieldAddr; + Modifier mod; + + if (compRefs) { + // until VM type system is upgraded, + // fieldDesc type will have uncompressed ref type; + // compress it + Type *compressedType = typeManager.compressType(fieldType); + fieldAddr = createOpnd(typeManager.getManagedPtrType(compressedType)); + mod = AutoCompress_Yes; + } else { + fieldAddr = createOpnd(typeManager.getManagedPtrType(fieldType)); + mod = AutoCompress_No; + } + appendInst(instFactory.makeLdFieldAddr(fieldAddr, base, fieldDesc)); + + Opnd* fieldVal = createOpnd(fieldType); + appendInst(instFactory.makeTauLdInd(mod, fieldType->tag, fieldVal, fieldAddr, + tauBaseNonNull, tauAddressInRange)); + return fieldVal; +} + + + +Opnd* +HLOAPIMagicIRBuilder::createOpnd(Type* type) { + if (type->tag == Type::Void) + return OpndManager::getNullOpnd(); + return opndManager.createSsaTmpOpnd(type); +} + +VarOpnd* +HLOAPIMagicIRBuilder::createVarOpnd(Type* type, bool isPinned) { + assert(type->tag != Type::Void); + return opndManager.createVarOpnd(type,isPinned); +} + +SsaVarOpnd* +HLOAPIMagicIRBuilder::createSsaVarOpnd(VarOpnd* var) { + return opndManager.createSsaVarOpnd(var); +} + +void +HLOAPIMagicIRBuilder::genStVar(SsaVarOpnd* var, Opnd* src) { + appendInst(instFactory.makeStVar(var, src)); +} + +Opnd* +HLOAPIMagicIRBuilder::genTauCheckNull(Opnd* base) +{ + Opnd* dst = createOpnd(typeManager.getTauType()); + Inst* inst = instFactory.makeTauCheckNull(dst, base); + appendInst(inst); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genAnd(Type* dstType, Opnd* src1, Opnd* src2) { + Opnd* dst = createOpnd(dstType); + appendInst(instFactory.makeAnd(dst, src1, src2)); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genTauAnd(Opnd *src1, Opnd *src2) { + if (src1->getId() > src2->getId()) { + Opnd *tmp = src1; + src1 = src2; + src2 = tmp; + } + Opnd* dst = createOpnd(typeManager.getTauType()); + Opnd* srcs[2] = { src1, src2 }; + appendInst(instFactory.makeTauAnd(dst, 2, srcs)); + + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genAdd(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { + Opnd* dst = createOpnd(dstType); + Inst *newi = instFactory.makeAdd(mod, dst, src1, src2); + appendInst(newi); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genSub(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { + Opnd* dst = createOpnd(dstType); + Inst *newi = instFactory.makeSub(mod, dst, src1, src2); + appendInst(newi); + return dst; +} + + +Opnd* +HLOAPIMagicIRBuilder::genLdConstant(int32 val) { + Opnd* dst = createOpnd(typeManager.getInt32Type()); + appendInst(instFactory.makeLdConst(dst, val)); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genArrayLen(Type* dstType, Type::Tag type, Opnd* array, Opnd* tauNonNull) { + Opnd *tauIsArray = genTauHasType(array, array->getType()); + + return genTauArrayLen(dstType, type, array, tauNonNull, tauIsArray); +} + +Opnd* +HLOAPIMagicIRBuilder::genTauArrayLen(Type* dstType, Type::Tag type, Opnd* array, + Opnd* tauNullChecked, Opnd *tauTypeChecked) { + Opnd* dst = createOpnd(dstType); + appendInst(instFactory.makeTauArrayLen(dst, type, array, tauNullChecked, + tauTypeChecked)); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genCmp3(Type* dstType, + Type::Tag instType, // source type for inst + ComparisonModifier mod, + Opnd* src1, + Opnd* src2) { + // result of comparison is always a 32-bit int + Opnd* dst = createOpnd(dstType); + Inst* i = instFactory.makeCmp3(mod, instType, dst, src1, src2); + appendInst(i); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genCmp(Type* dstType, + Type::Tag instType, // source type for inst + ComparisonModifier mod, + Opnd* src1, + Opnd* src2) { + // result of comparison is always a 32-bit int + Opnd* dst = createOpnd(dstType); + Inst *i = instFactory.makeCmp(mod, instType, dst, src1, src2); + appendInst(i); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genTauSafe() { + Opnd* dst = createOpnd(typeManager.getTauType()); + appendInst(instFactory.makeTauSafe(dst)); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genTauCheckBounds(Opnd* array, Opnd* index, Opnd *tauNullChecked) { + Opnd *tauArrayTypeChecked = genTauHasType(array, array->getType()); + Opnd* arrayLen = genTauArrayLen(typeManager.getInt32Type(), Type::Int32, array, + tauNullChecked, tauArrayTypeChecked); + + Opnd* dst = genTauCheckBounds(arrayLen, index); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genTauCheckBounds(Opnd* ub, Opnd *index) { + Opnd* dst = createOpnd(typeManager.getTauType()); + appendInst(instFactory.makeTauCheckBounds(dst, ub, index)); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genTauHasType(Opnd *src, Type *castType) { + Opnd* dst = createOpnd(typeManager.getTauType()); + appendInst(instFactory.makeTauHasType(dst, src, castType)); + return dst; +} + +Opnd* +HLOAPIMagicIRBuilder::genIntrinsicCall(IntrinsicCallId intrinsicId, + Type* returnType, + Opnd* tauNullCheckedRefArgs, + Opnd* tauTypesChecked, + uint32 numArgs, + Opnd* args[]) { + Opnd * dst = createOpnd(returnType); + appendInst(instFactory.makeIntrinsicCall(dst, intrinsicId, + tauNullCheckedRefArgs, + tauTypesChecked, + numArgs, args)); + return dst; +} + +} //namespace Jitrino Index: vm/jitrino/src/optimizer/HLOAPIMagics.h =================================================================== --- vm/jitrino/src/optimizer/HLOAPIMagics.h (revision 0) +++ vm/jitrino/src/optimizer/HLOAPIMagics.h (revision 0) @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, George A. Timoshenko + */ + +#ifndef _HLOAPIMAGICS_H_ +#define _HLOAPIMAGICS_H_ + +#include "optpass.h" +#include "Inst.h" +#include "irmanager.h" + +namespace Jitrino { + +class HLOAPIMagicIRBuilder { +public: + HLOAPIMagicIRBuilder(IRManager* irmanager, MemoryManager& _mm, bool _compRefs) + : irm(irmanager), + instFactory(irm->getInstFactory()), + opndManager(irm->getOpndManager()), + typeManager(irm->getTypeManager()), + cfg(irm->getFlowGraph()), + mm(_mm), + compRefs(_compRefs), + currentNode(NULL), + currentBCOffset(ILLEGAL_BC_MAPPING_VALUE) + {} + +public: + IRManager* getIRManager() {return irm;} + InstFactory& getInstFactory() {return instFactory;} + OpndManager& getOpndManager() {return opndManager;} + TypeManager& getTypeManager() {return typeManager;} + ControlFlowGraph& getControlFlowGraph() {return cfg;} + MemoryManager& getMemoryManager() {return mm;} + + // Flow Graph building + Node* getCurrentNode() {return currentNode;} + void setCurrentNode(Node* node) {currentNode = node;} + uint16 getCurrentBCOffset() {return currentBCOffset;} + void setCurrentBCOffset(uint16 offset) {currentBCOffset = offset;} + + void genEdgeFromCurrent(Node* target) {cfg.addEdge(currentNode, target);} + void genEdgeToCurrent(Node* source) {cfg.addEdge(source,currentNode);} + + Node* genNodeAfter(Node* node, LabelInst* label, Node* dispatch=NULL); + Node* genNodeAfterCurrent(LabelInst* label, Node* dispatch=NULL); + Node* genFallthroughNode(Node* dispatch=NULL); + + // IR building + void appendInst(Inst* inst); + void genCopy(Opnd* trgt, Opnd* src); + Opnd* genLdField(FieldDesc* fieldDesc, Opnd* base, Opnd* tauBaseNonNull, Opnd* tauAddressInRange); + Opnd* createOpnd(Type* type); + VarOpnd* createVarOpnd(Type* type, bool isPinned); + SsaVarOpnd* createSsaVarOpnd(VarOpnd* var); + void genStVar(SsaVarOpnd* var, Opnd* src); + Opnd* genTauCheckNull(Opnd* base); + Opnd* genAnd(Type* dstType, Opnd* src1, Opnd* src2); + Opnd* genTauAnd(Opnd* src1, Opnd* src2); + Opnd* genAdd(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2); + Opnd* genSub(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2); + Opnd* genLdConstant(int32 val); + Opnd* genArrayLen(Type* dstType, Type::Tag type, Opnd* array, Opnd* tauNonNull); + Opnd* genTauArrayLen(Type* dstType, Type::Tag type, Opnd* array, + Opnd* tauNullChecked, Opnd *tauTypeChecked); + Opnd* genCmp3(Type* dstType, Type::Tag instType, // source type for inst + ComparisonModifier mod, Opnd* src1, Opnd* src2); + Opnd* genCmp(Type* dstType, Type::Tag instType, // source type for inst + ComparisonModifier mod, Opnd* src1, Opnd* src2); + Opnd* genTauSafe(); + Opnd* genTauCheckBounds(Opnd* array, Opnd* index, Opnd *tauNullChecked); + Opnd* genTauCheckBounds(Opnd* ub, Opnd *index); + Opnd* genTauHasType(Opnd *src, Type *castType); + Opnd* genIntrinsicCall(IntrinsicCallId intrinsicId, Type* returnType, Opnd* tauNullCheckedRefArgs, + Opnd* tauTypesChecked, uint32 numArgs, Opnd* args[]); + +private: + IRManager* irm; + InstFactory& instFactory; + OpndManager& opndManager; + TypeManager& typeManager; + ControlFlowGraph& cfg; + MemoryManager& mm; + bool compRefs; + Node* currentNode; + uint16 currentBCOffset; +}; + +class HLOAPIMagicHandler { +public: + HLOAPIMagicHandler(MethodCallInst* inst) + : callInst(inst) + {} + void setIRBuilder(HLOAPIMagicIRBuilder* irb) {builder = irb;} + virtual void run() = 0; + +protected: + HLOAPIMagicIRBuilder* builder; + MethodCallInst* callInst; +}; + +#define DECLARE_HLO_MAGIC_INLINER(name)\ +class name : public HLOAPIMagicHandler {\ +public:\ + name (MethodCallInst* inst)\ + : HLOAPIMagicHandler(inst){}\ + \ + virtual void run();\ +};\ + +DECLARE_HLO_MAGIC_INLINER(String_compareTo_HLO_Handler); +DECLARE_HLO_MAGIC_INLINER(String_regionMatches_HLO_Handler); + +DEFINE_SESSION_ACTION(HLOAPIMagicSession, hlo_api_magic, "APIMagics HLO Pass") + +void +HLOAPIMagicSession::_run(IRManager& irm) +{ + MemoryManager mm("HLOAPIMagicSession mm"); + + //finding all api magic calls + StlVector handlers(mm); + ControlFlowGraph& fg = irm.getFlowGraph(); + const Nodes& nodes = fg.getNodesPostOrder();//process checking only reachable nodes. + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { + if (inst->getOpcode() != Op_DirectCall) { + continue; + } + MethodCallInst* callInst = (MethodCallInst*)inst; + MethodDesc* md = callInst->getMethodDesc(); + const char* className = md->getParentType()->getName(); + const char* methodName = md->getName(); + const char* signature = md->getSignatureString(); + if (!strcmp(className, "java/lang/String")) { + if (!strcmp(methodName, "compareTo") && !strcmp(signature, "(Ljava/lang/String;)I")) { + if(getBoolArg("String_compareTo_as_magic", true)) + handlers.push_back(new (mm) String_compareTo_HLO_Handler(callInst)); + } else if (!strcmp(methodName, "regionMatches") && !strcmp(signature, "(ILjava/lang/String;II)Z")) { + if(getBoolArg("String_regionMatches_as_magic", true)) + handlers.push_back(new (mm) String_regionMatches_HLO_Handler(callInst)); + } + } + } + } + } + + if(handlers.size() != 0) { + bool compRefs = getBoolArg("compressedReferences", false); + HLOAPIMagicIRBuilder builder = HLOAPIMagicIRBuilder(&irm, mm, compRefs); + //running all handlers + for (StlVector::const_iterator it = handlers.begin(), end = handlers.end(); it!=end; ++it) { + HLOAPIMagicHandler* handler = *it; + handler->setIRBuilder(&builder); + handler->run(); + } + } +} + + + + + + +} //namespace Jitrino + +#endif // _HLOAPIMAGICS_H_ Index: vm/jitrino/src/optimizer/escanalyzer.cpp =================================================================== --- vm/jitrino/src/optimizer/escanalyzer.cpp (revision 584779) +++ vm/jitrino/src/optimizer/escanalyzer.cpp (working copy) @@ -413,6 +413,8 @@ case ReadThisState: case LockedCompareAndExchange: case AddValueProfileValue: + case StringCompareTo: + case StringRegionMatches: break; default: assert(0); Index: vm/jitrino/src/optimizer/Inst.cpp =================================================================== --- vm/jitrino/src/optimizer/Inst.cpp (revision 584779) +++ vm/jitrino/src/optimizer/Inst.cpp (working copy) @@ -476,6 +476,10 @@ os << "AddValueProfileValue"; break; case FillArrayWithConst: os << "FillArrayWithConst"; break; + case StringCompareTo: + os << "StringCompareTo"; break; + case StringRegionMatches: + os << "StringRegionMatches"; break; default: assert(0); break; } Index: vm/jitrino/src/optimizer/CodeSelectors.cpp =================================================================== --- vm/jitrino/src/optimizer/CodeSelectors.cpp (revision 584779) +++ vm/jitrino/src/optimizer/CodeSelectors.cpp (working copy) @@ -403,12 +403,14 @@ JitHelperCallOp::Id _BlockCodeSelector::convertJitHelperId(JitHelperCallId callId) { switch(callId) { - case InitializeArray: return JitHelperCallOp::InitializeArray; - case SaveThisState: return JitHelperCallOp::SaveThisState; - case ReadThisState: return JitHelperCallOp::ReadThisState; - case LockedCompareAndExchange: return JitHelperCallOp::LockedCompareAndExchange; - case AddValueProfileValue: return JitHelperCallOp::AddValueProfileValue; - case FillArrayWithConst: return JitHelperCallOp::FillArrayWithConst; + case InitializeArray: return JitHelperCallOp::InitializeArray; + case SaveThisState: return JitHelperCallOp::SaveThisState; + case ReadThisState: return JitHelperCallOp::ReadThisState; + case LockedCompareAndExchange: return JitHelperCallOp::LockedCompareAndExchange; + case AddValueProfileValue: return JitHelperCallOp::AddValueProfileValue; + case FillArrayWithConst: return JitHelperCallOp::FillArrayWithConst; + case StringCompareTo: return JitHelperCallOp::StringCompareTo; + case StringRegionMatches: return JitHelperCallOp::StringRegionMatches; } assert(0); return JitHelperCallOp::InitializeArray; // to keep compiler quiet Index: vm/jitrino/src/optimizer/inliner.cpp =================================================================== --- vm/jitrino/src/optimizer/inliner.cpp (revision 584779) +++ vm/jitrino/src/optimizer/inliner.cpp (working copy) @@ -134,6 +134,12 @@ _inlineSkipMethodTable->add_method_record("java/lang/Integer", "numberOfTrailingZeros", "(I)I", des, false); _inlineSkipMethodTable->add_method_record("java/lang/Long", "numberOfLeadingZeros", "(J)I", des, false); _inlineSkipMethodTable->add_method_record("java/lang/Long", "numberOfTrailingZeros", "(J)I", des, false); + if(argSource->getBoolArg("String_compareTo_as_magic",true)) { + _inlineSkipMethodTable->add_method_record("java/lang/String", "compareTo", "(Ljava/lang/String;)I", des, false); + } + if(argSource->getBoolArg("String_regionMatches_as_magic",true)) { + _inlineSkipMethodTable->add_method_record("java/lang/String", "regionMatches", "(ILjava/lang/String;II)Z", des, false); + } #endif } } Index: vm/jitrino/src/optimizer/deadcodeeliminator.cpp =================================================================== --- vm/jitrino/src/optimizer/deadcodeeliminator.cpp (revision 584779) +++ vm/jitrino/src/optimizer/deadcodeeliminator.cpp (working copy) @@ -354,7 +354,16 @@ DeadCodeEliminator::copyPropagate(Inst* inst) { uint32 numSrcs = inst->getNumSrcOperands(); for (uint32 i=0; isetSrc(i, copyPropagate(inst->getSrc(i))); + Opnd* opnd = inst->getSrc(i); + Opnd* propagated = copyPropagate(opnd); + if (opnd != propagated) { + if (Log::isEnabled()) { + Log::out() << " Operand "; opnd->print(Log::out()); + Log::out() << " replaced by "; propagated->print(Log::out()); + Log::out() << std::endl; + } + inst->setSrc(i, propagated); + } } } Index: vm/jitrino/src/optimizer/Opcode.h =================================================================== --- vm/jitrino/src/optimizer/Opcode.h (revision 584779) +++ vm/jitrino/src/optimizer/Opcode.h (working copy) @@ -275,7 +275,9 @@ SaveThisState, //todo: replace with GetTLS + offset sequence ReadThisState, //todo: replace with GetTLS + offset sequence LockedCompareAndExchange, - AddValueProfileValue + AddValueProfileValue, + StringCompareTo, + StringRegionMatches }; enum Opcode { Index: vm/jitrino/src/optimizer/memoryopt.cpp =================================================================== --- vm/jitrino/src/optimizer/memoryopt.cpp (revision 584779) +++ vm/jitrino/src/optimizer/memoryopt.cpp (working copy) @@ -666,6 +666,8 @@ case ReadThisState: case LockedCompareAndExchange: case AddValueProfileValue: + case StringCompareTo: + case StringRegionMatches: break; default: assert(0); Index: vm/jitrino/src/vm/VMInterface.cpp =================================================================== --- vm/jitrino/src/vm/VMInterface.cpp (revision 584779) +++ vm/jitrino/src/vm/VMInterface.cpp (working copy) @@ -872,6 +872,19 @@ return getFieldDesc(res); } +MethodDesc* +CompilationInterface::getMethodByName(Class_Handle enclClass, const char* name) { + Method_Handle res = class_get_method_by_name(enclClass, name); + assert(res != NULL); // this functionality should be used only for those resolved for sure + return getMethodDesc(res); +} + +FieldDesc* +CompilationInterface::getFieldByName(Class_Handle enclClass, const char* name) { + Field_Handle res = class_get_field_by_name(enclClass, name); + return res == NULL ? NULL : getFieldDesc(res); +} + Type* CompilationInterface::getFieldType(Class_Handle enclClass, uint32 cpIndex) { Java_Type drlType = (Java_Type)class_get_cp_field_type(enclClass, (unsigned short)cpIndex); Index: vm/jitrino/src/vm/VMInterface.h =================================================================== --- vm/jitrino/src/vm/VMInterface.h (revision 584779) +++ vm/jitrino/src/vm/VMInterface.h (working copy) @@ -328,6 +328,8 @@ FieldDesc* getNonStaticField(Class_Handle enclClass, uint32 cpIndex, bool putfield); FieldDesc* getStaticField(Class_Handle enclClass, uint32 cpIndex, bool putfield); + FieldDesc* getFieldByName(Class_Handle enclClass, const char* name); + MethodDesc* getMethodByName(Class_Handle enclClass, const char* name); // resolve-by-name methods Index: vm/jitrino/src/shared/ControlFlowGraph.h =================================================================== --- vm/jitrino/src/shared/ControlFlowGraph.h (revision 584779) +++ vm/jitrino/src/shared/ControlFlowGraph.h (working copy) @@ -1254,7 +1254,7 @@ /** * Orders the nodes in the graph. - * If isForwarisForward is TRUE, updates the + * If isForward is TRUE, updates the * internal CFG collection of nodes and node df-numbers. * Affects nodes and graph traversal and ordering numbers. * Index: vm/jitrino/src/translator/java/JavaByteCodeTranslator.h =================================================================== --- vm/jitrino/src/translator/java/JavaByteCodeTranslator.h (revision 584779) +++ vm/jitrino/src/translator/java/JavaByteCodeTranslator.h (working copy) @@ -56,7 +56,9 @@ void offset_done(uint32 offset); void checkStack(); // called before parsing starts - virtual void parseInit() {} + virtual void parseInit() { + if (Log::isEnabled()) Log::out() << ::std::endl << "================= TRANSLATOR STARTED =================" << ::std::endl << ::std::endl; + } // called after parsing ends, but not if an error occurs virtual void parseDone(); // called when an error occurs during the byte code parsing Index: vm/jitrino/src/translator/java/JavaLabelPrepass.cpp =================================================================== --- vm/jitrino/src/translator/java/JavaLabelPrepass.cpp (revision 584779) +++ vm/jitrino/src/translator/java/JavaLabelPrepass.cpp (working copy) @@ -610,6 +610,7 @@ labelOffsets = new (memManager) uint32[numLabels]; struct LabelOffsetVisitor avisitor(labelOffsets); labels->visitElems(avisitor); + if (Log::isEnabled()) Log::out() << ::std::endl << "================= PREPASS IS FINISHED =================" << ::std::endl << ::std::endl; } uint32 JavaLabelPrepass::getLabelId(uint32 offset) { Index: vm/jitrino/src/translator/java/JavaLabelPrepass.h =================================================================== --- vm/jitrino/src/translator/java/JavaLabelPrepass.h (revision 584779) +++ vm/jitrino/src/translator/java/JavaLabelPrepass.h (working copy) @@ -225,7 +225,9 @@ void parseError(); // called to initialize parsing - void parseInit() {} + void parseInit() { + if (Log::isEnabled()) Log::out() << ::std::endl << "================= PREPASS STARTED =================" << ::std::endl << ::std::endl; + } // called to indicate end of parsing void parseDone(); Index: vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp =================================================================== --- vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp (revision 584779) +++ vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp (working copy) @@ -562,6 +562,7 @@ jsrEntryMap->insert(std::make_pair(entry_inst, ret_inst)); } irBuilder.getIRManager()->setJsrEntryMap(jsrEntryMap); + if (Log::isEnabled()) Log::out() << ::std::endl << "================= TRANSLATOR IS FINISHED =================" << ::std::endl << ::std::endl; } //-----------------------------------------------------------------------------