Index: vm/jitrino/src/codegenerator/CodeGenIntfc.h =================================================================== --- vm/jitrino/src/codegenerator/CodeGenIntfc.h (revision 602903) +++ vm/jitrino/src/codegenerator/CodeGenIntfc.h (working copy) @@ -173,7 +173,8 @@ LockedCompareAndExchange, AddValueProfileValue, StringCompareTo, - StringRegionMatches + StringRegionMatches, + StringIndexOf }; }; Index: vm/jitrino/src/codegenerator/ia32/Ia32APIMagics.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32APIMagics.cpp (revision 602903) +++ vm/jitrino/src/codegenerator/ia32/Ia32APIMagics.cpp (working copy) @@ -84,6 +84,7 @@ 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); +DECLARE_HELPER_INLINER(String_indexOf_Handler_x_String_x_I_x_I); void APIMagicsHandlerSession::runImpl() { CompilationContext* cc = getCompilationContext(); @@ -135,6 +136,9 @@ } 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((char*)ri->getValue(0),"String_indexOf")==0 ) { + if(getBoolArg("String_indexOf_as_magic", true)) + handlers.push_back(new (tmpMM) String_indexOf_Handler_x_String_x_I_x_I(irm, callInst, NULL)); } } } @@ -495,8 +499,205 @@ callInst->unlink(); } -// this intends for indexes and counters conversion -// ATTENTION !!! Zero Extention is used for this +void String_indexOf_Handler_x_String_x_I_x_I::run() { + + Node* callInstNode = callInst->getNode(); + Node* nextNode = NULL; + + if(callInst == callInstNode->getLastInst()) { + nextNode = callInstNode->getUnconditionalEdgeTarget(); + assert(nextNode!=NULL); + } else { + nextNode = irm->getFlowGraph()->splitNodeAtInstruction(callInst, true, true, 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* thisOffset = getCallSrc(callInst, 1); + Opnd* thisLen = getCallSrc(callInst, 2); + Opnd* trgtArr = getCallSrc(callInst, 3); + Opnd* trgtOffset = getCallSrc(callInst, 4); + Opnd* trgtLen = getCallSrc(callInst, 5); + Opnd* start = getCallSrc(callInst, 6); + Opnd* res = getCallDst(callInst); + +#ifdef _EM64T_ + Type* counterType = irm->getTypeManager().getInt64Type(); + Constraint regConstr(OpndKind_GPReg, OpndSize_64); +#else + Type* counterType = irm->getTypeManager().getInt32Type(); + Constraint regConstr(OpndKind_GPReg, OpndSize_32); +#endif + Constraint reg16Constr(OpndKind_GPReg, OpndSize_16); + + Opnd* zero = irm->newImmOpnd(counterType, 0); + + Node* mainNode = irm->getFlowGraph()->createBlockNode(); + + Node* mainLoop = irm->getFlowGraph()->createBlockNode(); + Node* mainLoop2 = irm->getFlowGraph()->createBlockNode(); + Node* mainLoop3 = irm->getFlowGraph()->createBlockNode(); + Node* nestedLoop = irm->getFlowGraph()->createBlockNode(); + Node* nestedLoop2 = irm->getFlowGraph()->createBlockNode(); + Node* nestedLoop3 = irm->getFlowGraph()->createBlockNode(); + Node* mainLoopEnd = irm->getFlowGraph()->createBlockNode(); + + Node* returnStart = irm->getFlowGraph()->createBlockNode(); + Node* returnIndex = irm->getFlowGraph()->createBlockNode(); + Node* returnMinusOne = irm->getFlowGraph()->createBlockNode(); + + irm->getFlowGraph()->addEdge(mainNode, mainLoop); + + irm->getFlowGraph()->addEdge(mainLoop, mainLoop2, 0.9); + irm->getFlowGraph()->addEdge(mainLoop, returnMinusOne, 0.1); + irm->getFlowGraph()->addEdge(mainLoop2, mainLoop3, 0.1); + irm->getFlowGraph()->addEdge(mainLoop2, mainLoopEnd, 0.9); + irm->getFlowGraph()->addEdge(mainLoop3, nestedLoop); + irm->getFlowGraph()->addEdge(nestedLoop, returnIndex, 0.1); + irm->getFlowGraph()->addEdge(nestedLoop, nestedLoop2, 0.9); + irm->getFlowGraph()->addEdge(nestedLoop2, mainLoopEnd, 0.8); + irm->getFlowGraph()->addEdge(nestedLoop2, nestedLoop3, 0.2); + irm->getFlowGraph()->addEdge(nestedLoop3, nestedLoop); + irm->getFlowGraph()->addEdge(mainLoopEnd, mainLoop); + + irm->getFlowGraph()->addEdge(returnStart, nextNode); + irm->getFlowGraph()->addEdge(returnMinusOne, nextNode); + irm->getFlowGraph()->addEdge(returnIndex, nextNode); + + Opnd* subLen = irm->newOpnd(counterType, regConstr); + + bool startIsZero = true; + if ( !(start->isPlacedIn(OpndKind_Imm) && start->getImmValue() == 0) ) + startIsZero = false; + + if ( !start->isPlacedIn(OpndKind_Imm) ) + { + Node* startLessThanZero = irm->getFlowGraph()->createBlockNode(); + Node* subLenCheck = irm->getFlowGraph()->createBlockNode(); + Node* startCheck = irm->getFlowGraph()->createBlockNode(); + + irm->getFlowGraph()->addEdge(callInstNode, startLessThanZero, 0); + irm->getFlowGraph()->addEdge(callInstNode, subLenCheck, 1); + irm->getFlowGraph()->addEdge(startLessThanZero, subLenCheck); + irm->getFlowGraph()->addEdge(subLenCheck, startCheck, 0); + irm->getFlowGraph()->addEdge(subLenCheck, mainNode, 1); + irm->getFlowGraph()->addEdge(startCheck, returnMinusOne, 0); + irm->getFlowGraph()->addEdge(startCheck, returnStart, 1); + + callInstNode->appendInst(irm->newInst(Mnemonic_CMP, start, zero)); // cmp start, 0 + callInstNode->appendInst(irm->newBranchInst(Mnemonic_JL, startLessThanZero, subLenCheck)); // jl startLessThanZero + + startLessThanZero->appendInst(irm->newInst(Mnemonic_MOV, start, zero)); // mov start, 0 + + // saving subString.length on register + subLenCheck->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, subLen, trgtLen)); // mov subLen, subString.count + subLenCheck->appendInst(irm->newInst(Mnemonic_CMP, subLen, zero)); // cmp subLen, 0 + subLenCheck->appendInst(irm->newBranchInst(Mnemonic_JE, startCheck, mainNode)); // je startCheck + + startCheck->appendInst(irm->newInst(Mnemonic_CMP, start, thisLen)); // cmp start, this.count + startCheck->appendInst(irm->newBranchInst(Mnemonic_JG, returnMinusOne, returnStart)); // jg returnMinusOne + } + else // removing unnecessary checks + { + int64 val = start->getImmValue(); + if (val <0) + { + start = zero; + val = 0; + } + + // saving subString.length on register + callInstNode->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, subLen, trgtLen)); // mov subLen, subString.count + callInstNode->appendInst(irm->newInst(Mnemonic_CMP, subLen, zero)); // cmp subLen, 0 + + if (val != 0) + { + Node* startCheck = irm->getFlowGraph()->createBlockNode(); + + irm->getFlowGraph()->addEdge(callInstNode, mainNode, 1); + irm->getFlowGraph()->addEdge(callInstNode, startCheck, 0); + irm->getFlowGraph()->addEdge(startCheck, returnMinusOne, 0); + irm->getFlowGraph()->addEdge(startCheck, returnStart, 1); + + callInstNode->appendInst(irm->newBranchInst(Mnemonic_JE, startCheck, mainNode)); // je startCheck + + startCheck->appendInst(irm->newInst(Mnemonic_CMP, thisLen, start)); // cmp this.count, start + startCheck->appendInst(irm->newBranchInst(Mnemonic_JL, returnMinusOne, returnStart)); // jl returnMinusOne + } + else + { + irm->getFlowGraph()->addEdge(callInstNode, mainNode, 1); + irm->getFlowGraph()->addEdge(callInstNode, returnStart, 0); + callInstNode->appendInst(irm->newBranchInst(Mnemonic_JE, returnStart, mainNode)); // je returnStart + } + } + + // prepare this position + Opnd* offset = irm->newOpnd(counterType, regConstr); + mainNode->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, offset, thisOffset)); // mov offset, this.offset + if (!startIsZero) + mainNode->appendInst(irm->newInst(Mnemonic_ADD, offset, start)); // add offset, start + Opnd* thisAddrReg = addElemIndexWithLEA(thisArr, offset, mainNode); // lea edi, [this.value + offset*sizeof(char) + 12] + + // prepare trgt position + Opnd* trgtAddrReg = addElemIndexWithLEA(trgtArr, trgtOffset, mainNode); // lea esi, [subString.value + subString.offset*sizeof(char) + 12] + + // lastIndex = this.count - subString.count - start + Opnd* lastIndex = irm->newOpnd(counterType, regConstr); + mainNode->appendInst(irm->newCopyPseudoInst(Mnemonic_MOV, lastIndex, thisLen)); // mov lastIndex, this.count + mainNode->appendInst(irm->newInst(Mnemonic_SUB, lastIndex, subLen)); // sub lastIndex, subLen + if (!startIsZero) + mainNode->appendInst(irm->newInst(Mnemonic_SUB, lastIndex, start)); // sub lastIndex, start + + //save subString's first char + Opnd* firstChar = irm->newOpnd(irm->getTypeManager().getCharType(), reg16Constr); + mainNode->appendInst(irm->newInst(Mnemonic_MOV, firstChar, irm->newMemOpnd(irm->getTypeManager().getCharType(), trgtAddrReg, 0, 0, 0))); // mov firstChar, word ptr [esi] + + // preparing main loop iterator + Opnd* mainLoopIter = irm->newOpnd(counterType, regConstr); + mainNode->appendInst(irm->newInst(Mnemonic_MOV, mainLoopIter, zero)); // mov mainLoopIter, 0 + + //***************************************************************************************************** + + // main loop + mainLoop->appendInst(irm->newInst(Mnemonic_CMP, mainLoopIter, lastIndex)); // cmp mainLoopIter, lastIndex + mainLoop->appendInst(irm->newBranchInst(Mnemonic_JG, returnMinusOne, mainLoop2)); // jg returnMinusOne + + Opnd* currentChar = irm->newMemOpnd(irm->getTypeManager().getCharType(), thisAddrReg, 0, 0, 0); + mainLoop2->appendInst(irm->newInst(Mnemonic_CMP, currentChar, firstChar)); // cmp word ptr [edi], firstChar + mainLoop2->appendInst(irm->newBranchInst(Mnemonic_JNE, mainLoopEnd, mainLoop3)); // jne mainLoopEnd + + // preparing nested loop iterator + Opnd* nestedLoopIter = irm->newOpnd(counterType, regConstr); + mainLoop3->appendInst(irm->newInst(Mnemonic_MOV, nestedLoopIter, irm->newImmOpnd(counterType, 1))); // mov nestedLoopIter, 1 + + nestedLoop->appendInst(irm->newInst(Mnemonic_CMP, nestedLoopIter, subLen)); // cmp nestedLoopIter, subLen + nestedLoop->appendInst(irm->newBranchInst(Mnemonic_JGE, returnIndex, nestedLoop2)); // jge returnIndex + + Opnd* tmp = irm->newRegOpnd(irm->getTypeManager().getCharType(), RegName_DX); + nestedLoop2->appendInst(irm->newInst(Mnemonic_MOV, tmp, irm->newMemOpnd(irm->getTypeManager().getCharType(), thisAddrReg, nestedLoopIter, irm->newImmOpnd(counterType, 2), 0))); // mov tmp, [edi + 2*nestedLoopIter] + nestedLoop2->appendInst(irm->newInst(Mnemonic_CMP, tmp, irm->newMemOpnd(irm->getTypeManager().getCharType(), trgtAddrReg, nestedLoopIter, irm->newImmOpnd(counterType, 2), 0))); // cmp tmp, [esi + 2*nestedLoopIter] + nestedLoop2->appendInst(irm->newBranchInst(Mnemonic_JNE, mainLoopEnd, nestedLoop3)); // jne mainLoopEnd + + nestedLoop3->appendInst(irm->newInst(Mnemonic_ADD, nestedLoopIter, irm->newImmOpnd(counterType, 1))); // add nestedLoopIter, 1 + + mainLoopEnd->appendInst(irm->newInst(Mnemonic_ADD, mainLoopIter, irm->newImmOpnd(counterType, 1))); // add mainLoopIter, 1 + mainLoopEnd->appendInst(irm->newInst(Mnemonic_ADD, thisAddrReg, irm->newImmOpnd(counterType, 2))); // add edi, 2 + + returnMinusOne->appendInst(irm->newInst(Mnemonic_MOV, res, irm->newImmOpnd(res->getType(), -1))); + + returnStart->appendInst(irm->newInst(Mnemonic_MOV, res, start)); + + returnIndex->appendInst(irm->newInst(Mnemonic_MOV, res, mainLoopIter)); + + if (!startIsZero) + returnIndex->appendInst(irm->newInst(Mnemonic_ADD, res, start)); + + callInst->unlink(); +} + void APIMagicHandler::convertIntToInt(Opnd* dst, Opnd* src, Node* node) { Type* dstType = dst->getType(); @@ -558,5 +759,8 @@ return dst; } + }} //namespace + + Index: vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (revision 602903) +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (working copy) @@ -180,6 +180,7 @@ 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)); + irManager.registerInternalHelperInfo("String_indexOf", IRManager::InternalHelperInfo(NULL,&CallingConvention_STDCALL)); } //_______________________________________________________________________________________________________________ @@ -2458,7 +2459,7 @@ CG_OpndHandle** args, Type* retType, MethodDesc * desc) -{ +{ return tau_call(numArgs, args, retType, desc, getTauUnsafe(), getTauUnsafe()); } @@ -2571,6 +2572,7 @@ // does not fit into 32 bits). If on EM64T we set IntPtrType for target address here constraint resolver work makes all // calls a register-form ones. (Even for those with a short offset). But immediate calls are faster and takes // less space. We should keep them when it is possible. + Opnd * target=irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_MethodDirectAddr, desc); Opnd * retOpnd=createResultOpnd(retType); CallInst * callInst=irManager.newCallInst(target, irManager.getDefaultManagedCallingConvention(), @@ -2695,9 +2697,11 @@ break; } case InitializeArray: + { assert(numArgs == 4); appendInsts(irManager.newInternalRuntimeHelperCallInst("initialize_array", numArgs, (Opnd**)args, dstOpnd)); break; + } case SaveThisState: { assert(numArgs == 1); @@ -2782,11 +2786,20 @@ } case StringRegionMatches: { + //printf("%d \n", callId); 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; } + case StringIndexOf: + { + 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_indexOf", numArgs, newArgs, dstOpnd)); + break; + } + default: { assert(0); Index: vm/jitrino/src/optimizer/CodeSelectors.cpp =================================================================== --- vm/jitrino/src/optimizer/CodeSelectors.cpp (revision 602903) +++ vm/jitrino/src/optimizer/CodeSelectors.cpp (working copy) @@ -413,6 +413,7 @@ case FillArrayWithConst: return JitHelperCallOp::FillArrayWithConst; case StringCompareTo: return JitHelperCallOp::StringCompareTo; case StringRegionMatches: return JitHelperCallOp::StringRegionMatches; + case StringIndexOf: return JitHelperCallOp::StringIndexOf; default: break; } crash("\n JIT helper in not supported in LIR : %d\n", callId); Index: vm/jitrino/src/optimizer/escanalyzer.cpp =================================================================== --- vm/jitrino/src/optimizer/escanalyzer.cpp (revision 602903) +++ vm/jitrino/src/optimizer/escanalyzer.cpp (working copy) @@ -416,6 +416,7 @@ case LockedCompareAndExchange: case AddValueProfileValue: case StringCompareTo: + case StringIndexOf: case StringRegionMatches: case ClassIsArray: case ClassGetAllocationHandle: @@ -5884,3 +5885,6 @@ + + + Index: vm/jitrino/src/optimizer/HLOAPIMagics.cpp =================================================================== --- vm/jitrino/src/optimizer/HLOAPIMagics.cpp (revision 602903) +++ vm/jitrino/src/optimizer/HLOAPIMagics.cpp (working copy) @@ -241,6 +241,100 @@ cfg.orderNodes(true); } +void +String_indexOf_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); + Opnd* start = callInst->getSrc(4); + + 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); + FieldDesc* offsetDesc = irm->getCompilationInterface().getFieldByName(string,"offset"); + assert(offsetDesc); + + // 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); + + // node + builder->genFallthroughNode(); + Opnd* imm128 = builder->genLdConstant(128); + Opnd* imm64 = builder->genLdConstant(64); + Opnd *tauTrgtInRange = builder->genTauHasType(trgtStr, fieldCountDesc->getParentType()); + + // node + builder->genFallthroughNode(dispatch); + + // prefetch String objects + Opnd * voidDst = builder->createOpnd(irm->getTypeManager().getVoidType()); + Opnd* prefetchThis[] = {thisStr, imm128, imm64}; + builder->appendInst(instFactory.makeJitHelperCall(voidDst, Prefetch, 3, prefetchThis)); + + // node + builder->genFallthroughNode(dispatch); + + Opnd* prefetchTrgt[] = {trgtStr, imm128, imm64}; + builder->appendInst(instFactory.makeJitHelperCall(voidDst, Prefetch, 3, prefetchTrgt)); + + Opnd* thisLength = builder->genLdField(fieldCountDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* trgtLength = builder->genLdField(fieldCountDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + + Opnd* thisOffset = builder->genLdField(offsetDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* trgtOffset = builder->genLdField(offsetDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + + Opnd* thisValue = builder->genLdField(fieldValueDesc, thisStr, tauThisNullChecked, tauThisInRange); + Opnd* trgtValue = builder->genLdField(fieldValueDesc, trgtStr, tauTrgtNullChecked, tauTrgtInRange); + + // node + builder->genFallthroughNode(dispatch); + + // prefetch character arrays + Opnd* prefetchThisValue[] = {thisValue, imm128, imm64}; + builder->appendInst(instFactory.makeJitHelperCall(voidDst, Prefetch, 3, prefetchThisValue)); + + // node + builder->genFallthroughNode(dispatch); + + Opnd* prefetchTrgtValue[] = {trgtValue, imm128, imm64}; + builder->appendInst(instFactory.makeJitHelperCall(voidDst, Prefetch, 3, prefetchTrgtValue)); + + // node + builder->genFallthroughNode(dispatch); + + Opnd* opnds[] = {thisValue, thisOffset, thisLength, trgtValue, trgtOffset, trgtLength, start}; + // This helper call will be processed in Ia32ApiMagics pass + builder->appendInst(instFactory.makeJitHelperCall(dst, StringIndexOf, 7, opnds)); + + builder->genEdgeFromCurrent(lastNode); + + cfg.orderNodes(true); +} + Node* HLOAPIMagicIRBuilder::genNodeAfter(Node* srcNode, LabelInst* label, Node* dispatch) { currentNode = cfg.createBlockNode(label); @@ -300,8 +394,6 @@ return fieldVal; } - - Opnd* HLOAPIMagicIRBuilder::createOpnd(Type* type) { if (type->tag == Type::Void) Index: vm/jitrino/src/optimizer/HLOAPIMagics.h =================================================================== --- vm/jitrino/src/optimizer/HLOAPIMagics.h (revision 602903) +++ vm/jitrino/src/optimizer/HLOAPIMagics.h (working copy) @@ -128,6 +128,7 @@ DECLARE_HLO_MAGIC_INLINER(String_compareTo_HLO_Handler); DECLARE_HLO_MAGIC_INLINER(String_regionMatches_HLO_Handler); +DECLARE_HLO_MAGIC_INLINER(String_indexOf_HLO_Handler); DEFINE_SESSION_ACTION(HLOAPIMagicSession, hlo_api_magic, "APIMagics HLO Pass") @@ -159,6 +160,9 @@ } 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)); + } else if (!strcmp(methodName, "indexOf") && !strcmp(signature, "(Ljava/lang/String;I)I")) { + if(getBoolArg("String_indexOf_as_magic", true)) + handlers.push_back(new (mm) String_indexOf_HLO_Handler(callInst)); } } } Index: vm/jitrino/src/optimizer/inliner.cpp =================================================================== --- vm/jitrino/src/optimizer/inliner.cpp (revision 602903) +++ vm/jitrino/src/optimizer/inliner.cpp (working copy) @@ -136,6 +136,7 @@ _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); + #endif if(argSource->getBoolArg("String_compareTo_as_magic",true)) { _inlineSkipMethodTable->add_method_record("java/lang/String", "compareTo", "(Ljava/lang/String;)I", des, false); @@ -143,6 +144,9 @@ if(argSource->getBoolArg("String_regionMatches_as_magic",true)) { _inlineSkipMethodTable->add_method_record("java/lang/String", "regionMatches", "(ILjava/lang/String;II)Z", des, false); } + if(argSource->getBoolArg("String_indexOf_as_magic",true)) { + _inlineSkipMethodTable->add_method_record("java/lang/String", "indexOf", "(Ljava/lang/String;I)I", des, false); + } #endif } } Index: vm/jitrino/src/optimizer/Inst.cpp =================================================================== --- vm/jitrino/src/optimizer/Inst.cpp (revision 602903) +++ vm/jitrino/src/optimizer/Inst.cpp (working copy) @@ -482,6 +482,8 @@ os << "FillArrayWithConst"; break; case StringCompareTo: os << "StringCompareTo"; break; + case StringIndexOf: + os << "StringIndexOf"; break; case StringRegionMatches: os << "StringRegionMatches"; break; case ClassIsArray: @@ -2069,6 +2071,7 @@ Modifier mod; switch(id) { case StringCompareTo: + case StringIndexOf: case StringRegionMatches: mod = Modifier(Exception_Never); break; Index: vm/jitrino/src/optimizer/memoryopt.cpp =================================================================== --- vm/jitrino/src/optimizer/memoryopt.cpp (revision 602903) +++ vm/jitrino/src/optimizer/memoryopt.cpp (working copy) @@ -669,6 +669,7 @@ case LockedCompareAndExchange: case AddValueProfileValue: case StringCompareTo: + case StringIndexOf: case StringRegionMatches: case FillArrayWithConst: case ClassIsArray: Index: vm/jitrino/src/optimizer/Opcode.h =================================================================== --- vm/jitrino/src/optimizer/Opcode.h (revision 602903) +++ vm/jitrino/src/optimizer/Opcode.h (working copy) @@ -280,6 +280,7 @@ AddValueProfileValue, StringCompareTo, StringRegionMatches, + StringIndexOf, ClassIsArray, ClassGetAllocationHandle, ClassGetTypeSize,