Index: vm/jitrino/src/codegenerator/ia32/Ia32Inst.h =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32Inst.h (revision 476055) +++ vm/jitrino/src/codegenerator/ia32/Ia32Inst.h (working copy) @@ -697,7 +697,22 @@ /** Returns true if the instruction has side effect not described by its operands */ virtual bool hasSideEffect()const - { return false; } + { + Mnemonic m = getMnemonic(); + if(m==Mnemonic_MOVS8 || + m==Mnemonic_MOVS16 || + m==Mnemonic_MOVS32 || + m==Mnemonic_STD || + m==Mnemonic_CLD || + m==Mnemonic_POPFD || + m==Mnemonic_PUSHFD || + m==Mnemonic_POP || + m==Mnemonic_PUSH ) + { + return true; + } + return false; + } /* Checks that inst is valid*/ virtual void verify() const { assert(node!=NULL);} Index: vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp (revision 476064) +++ vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp (working copy) @@ -1749,6 +1749,10 @@ stackDepth+=getByteSize(inst->getOpnd(it)->getSize()); } else if (inst->getMnemonic() == Mnemonic_POP) { stackDepth-=getByteSize(inst->getOpnd(it)->getSize()); + } else if (inst->getMnemonic() == Mnemonic_PUSHFD) { + stackDepth+=4; + } else if (inst->getMnemonic() == Mnemonic_POPFD) { + stackDepth-=4; } else if (inst->getMnemonic() == Mnemonic_CALL && ((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()) { stackDepth -= ((CallInst *)inst)->getArgStackDepth(); } Index: vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (revision 476064) +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (working copy) @@ -1836,7 +1836,44 @@ //_______________________________________________________________________________________________________________ // Compute address of the array element given // address of the first element and index +// using 'LEA' instruction +CG_OpndHandle* InstCodeSelector::addElemIndexWithLEA(Type * eType, + CG_OpndHandle * array, + CG_OpndHandle * index) +{ + ArrayType * arrayType=((Opnd*)array)->getType()->asArrayType(); + Type * elemType=arrayType->getElementType(); + Type * dstType=irManager.getManagedPtrType(elemType); + + uint32 elemSize = getByteSize(irManager.getTypeSize(elemType)); + + +#ifdef _EM64T_ + Type * indexType = typeManager.getInt64Type(); + Type * offType = typeManager.getInt64Type(); +#else + Type * indexType = typeManager.getInt32Type(); + Type * offType = typeManager.getInt32Type(); +#endif + + Opnd * indexOpnd = (Opnd *)index; + indexOpnd = convert(indexOpnd, indexType); + + Opnd * addr = irManager.newMemOpnd(dstType,(Opnd*)array, (Opnd*)index, + irManager.newImmOpnd(indexType, elemSize), + irManager.newImmOpnd(offType, arrayType->getArrayElemOffset()) + ); + Opnd * dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_LEA, 1, dst, addr)); + return dst; +} + +//_______________________________________________________________________________________________________________ +// Compute address of the array element given +// address of the first element and index +// using 'ADD' instruction + CG_OpndHandle* InstCodeSelector::addElemIndex(Type * eType, CG_OpndHandle * elemBase, CG_OpndHandle * index) @@ -2499,6 +2536,107 @@ } //_______________________________________________________________________________________________________________ +// reverse copying with 'rep move' instruction +// start indexes (args[1] and args[3] must be prepared respectively) + +CG_OpndHandle* InstCodeSelector::arraycopyReverse(uint32 numArgs, + CG_OpndHandle** args) +{ + + + appendInsts(irManager.newInst(Mnemonic_PUSHFD)); + appendInsts(irManager.newInst(Mnemonic_STD)); + + arraycopy(numArgs,args); + + appendInsts(irManager.newInst(Mnemonic_POPFD)); + + return NULL; +} + +//_______________________________________________________________________________________________________________ +// Transforming System::arraycopy call into 'rep move' + +CG_OpndHandle* InstCodeSelector::arraycopy(uint32 numArgs, + CG_OpndHandle** args) +{ + assert(numArgs == 5); + +#ifdef _EM64T_ + RegName counterRegName = RegName_RCX; + RegName srcAddrRegName = RegName_RSI; + RegName dstAddrRegName = RegName_RDI; +#else + RegName counterRegName = RegName_ECX; + RegName srcAddrRegName = RegName_ESI; + RegName dstAddrRegName = RegName_EDI; +#endif + + // prepare counter + Type* counterType = typeManager.getInt32Type(); + Opnd* counter = irManager.newRegOpnd(counterType,counterRegName); + copyOpnd(counter,(Opnd*)args[4]); + + // prepare src position + Opnd* srcAddr = (Opnd*)addElemIndexWithLEA(NULL,args[0],args[1]); + Opnd* srcAddrReg = irManager.newRegOpnd(srcAddr->getType(),srcAddrRegName); + copyOpnd(srcAddrReg,srcAddr); + + // prepare dst position + Opnd* dstAddr = (Opnd*)addElemIndexWithLEA(NULL,args[2],args[3]); + Opnd* dstAddrReg = irManager.newRegOpnd(dstAddr->getType(),dstAddrRegName); + copyOpnd(dstAddrReg,dstAddr); + + // double counter if elem type is 64 bits long + PtrType* srcAddrType = srcAddr->getType()->asPtrType(); + assert(srcAddrType); + Type::Tag tag = srcAddrType->getPointedToType()->tag; + Mnemonic mn = Mnemonic_NULL; + switch(tag) { + case Type::Int8 : + case Type::UInt8 : + case Type::Boolean: + { + mn = Mnemonic_MOVS8; break; + } + case Type::Char : + case Type::Int16 : + case Type::UInt16 : + { + mn = Mnemonic_MOVS16; break; + } + case Type::IntPtr : + case Type::Int32 : + case Type::UIntPtr: + case Type::UInt32 : + case Type::Single : + case Type::Float : + case Type::Object : + case Type::SystemObject : + case Type::SystemString : + case Type::Array : + { + mn = Mnemonic_MOVS32; break; + } + case Type::Int64 : + case Type::UInt64 : + case Type::Double : + { + appendInsts(irManager.newInst(Mnemonic_SHL, counter, irManager.newImmOpnd(counterType, (int32)1))); + mn = Mnemonic_MOVS32; break; + } + default: + assert(0); + mn = Mnemonic_MOVS32; break; + } + + Inst* copyInst = irManager.newInst(mn,dstAddrReg,srcAddrReg,counter); + copyInst->setPrefix(InstPrefix_REP); + appendInsts(copyInst); + return NULL; +} + +//_______________________________________________________________________________________________________________ // Direct call to the method. Depending on the code generator flags we // either expand direct call into loading method address into a register and // indirect call or true direct call that will be patched if method is recompiled. Index: vm/jitrino/src/codegenerator/ia32/Ia32Encoder.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32Encoder.cpp (revision 476064) +++ vm/jitrino/src/codegenerator/ia32/Ia32Encoder.cpp (working copy) @@ -276,9 +276,7 @@ break; } } - if (inst->getId() == 12) { - // raise(SIGTRAP); - } + return (uint8*)EncoderBase::encode((char*)stream, mnemonic, args); } Index: vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp (revision 476064) +++ vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp (working copy) @@ -439,7 +439,16 @@ int32 offset = MPTR_OFFSET_UNKNOWN; assert(fromOpnd->getType()->isObject() || fromOpnd->getType()->isManagedPtr()); uint32 useIndex2 = opnds.next(useIndex1); - if (useIndex2 < opnds.end()) { + if (inst->getMnemonic() == Mnemonic_LEA) { + assert(fromOpnd->isPlacedIn(OpndKind_Memory)); + Opnd* scaleOpnd = fromOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Scale); + if (scaleOpnd == NULL) { + Opnd* displOpnd = fromOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + assert(displOpnd!=NULL); + offset = (int32)displOpnd->getImmValue(); + } + fromOpnd = fromOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); + } else if (useIndex2 < opnds.end()) { Opnd* offsetOpnd = inst->getOpnd(useIndex2); offset = getOffsetFromImmediate(offsetOpnd); } @@ -449,7 +458,10 @@ } else { // mode == MODE_2_CALC_OFFSETS - 2 addr form //we can't rely on base/mptr type info here. //algorithm: - if (inst->hasKind(Inst::Kind_ControlTransferInst)) { + if (inst->hasKind(Inst::Kind_ControlTransferInst) || + inst->getMnemonic() == Mnemonic_MOVS8 || + inst->getMnemonic() == Mnemonic_MOVS16 || + inst->getMnemonic() == Mnemonic_MOVS32 ) { //Do nothing, calls return only bases } else { Opnd* fromOpnd = NULL; @@ -491,6 +503,7 @@ } else { offset = MPTR_OFFSET_UNKNOWN; } + fromOpnd = fromOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); } break; default: assert(0); @@ -501,7 +514,7 @@ if (fromPair != NULL || offset!=0) {//opnd is mptr -> update pairs updateMptrInfoInPairs(res, opnd, fromOpnd, offset, fromPair == NULL); } else { - //new def of base -> we must to remove all pairs where opnd acts as base or mptr + //new def of base -> we must remove all pairs where opnd acts as base or mptr //the problem is that in MODE2 we do not save info about bases (no ambiguity resolution is done) //so we can't match pairs where opnd is a base. //Solution: let pairs derived from this base to live, due to the fact that Index: vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.h =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.h (revision 476064) +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.h (working copy) @@ -156,6 +156,7 @@ CG_OpndHandle* ldStaticAddr(Type* fieldRefType,FieldDesc *desc); CG_OpndHandle* ldElemBaseAddr(CG_OpndHandle *array); CG_OpndHandle* addElemIndex(Type*, CG_OpndHandle *elemBase,CG_OpndHandle* index); + CG_OpndHandle* addElemIndexWithLEA(Type*, CG_OpndHandle *elemBase,CG_OpndHandle* index); CG_OpndHandle* ldElemAddr(CG_OpndHandle* array,CG_OpndHandle* index) { return addElemIndex(NULL,ldElemBaseAddr(array),index); } @@ -215,6 +216,8 @@ CG_OpndHandle* tauTypesChecked, InlineInfo* ii = NULL); CG_OpndHandle* call(uint32 numArgs, CG_OpndHandle** args, Type* retType, MethodDesc *desc, InlineInfo* ii = NULL); + CG_OpndHandle* arraycopyReverse(uint32 numArgs, CG_OpndHandle** args); + CG_OpndHandle* arraycopy(uint32 numArgs, CG_OpndHandle** args); CG_OpndHandle* tau_call(uint32 numArgs, CG_OpndHandle** args, Type* retType, MethodDesc *desc, CG_OpndHandle *nonNullFirstArgTau, CG_OpndHandle *tauTypesChecked, InlineInfo* ii = NULL); Index: vm/jitrino/src/codegenerator/CodeGenIntfc.h =================================================================== --- vm/jitrino/src/codegenerator/CodeGenIntfc.h (revision 476064) +++ vm/jitrino/src/codegenerator/CodeGenIntfc.h (working copy) @@ -156,7 +156,9 @@ class IntrinsicCallOp { public: enum Id { - CharArrayCopy + CharArrayCopy, + ArrayCopyDirect, + ArrayCopyReverse }; }; @@ -267,6 +269,8 @@ NamedType* vtableType) = 0; virtual CG_OpndHandle* call(uint32 numArgs, CG_OpndHandle** args, Type* retType, MethodDesc *desc, InlineInfo* ii = NULL) = 0; + virtual CG_OpndHandle* arraycopyReverse(uint32 numArgs, CG_OpndHandle** args) = 0; + virtual CG_OpndHandle* arraycopy(uint32 numArgs, CG_OpndHandle** args) = 0; virtual CG_OpndHandle* tau_call(uint32 numArgs, CG_OpndHandle** args, Type* retType, MethodDesc *desc, CG_OpndHandle *tauNullChecked, @@ -345,6 +349,7 @@ virtual CG_OpndHandle* ldStaticAddr(Type* fieldRefType,FieldDesc *desc) = 0; virtual CG_OpndHandle* ldElemBaseAddr(CG_OpndHandle* array) = 0; virtual CG_OpndHandle* addElemIndex(Type*, CG_OpndHandle *elemBase,CG_OpndHandle* index) = 0; + virtual CG_OpndHandle* addElemIndexWithLEA(Type*, CG_OpndHandle *elemBase,CG_OpndHandle* index) = 0; virtual CG_OpndHandle* ldElemAddr(CG_OpndHandle* array,CG_OpndHandle* index) = 0; // COMPRESSED_PTR note: // if we are using compressed references, and ptr is Ptr, then Index: vm/jitrino/src/optimizer/CodeGenerator.cpp =================================================================== --- vm/jitrino/src/optimizer/CodeGenerator.cpp (revision 476064) +++ vm/jitrino/src/optimizer/CodeGenerator.cpp (working copy) @@ -428,7 +428,9 @@ // IntrinsicCallOp::Id convertIntrinsicId(IntrinsicCallId callId) { switch(callId) { - case CharArrayCopy: return IntrinsicCallOp::CharArrayCopy; + case CharArrayCopy: return IntrinsicCallOp::CharArrayCopy; + case ArrayCopyDirect: return IntrinsicCallOp::ArrayCopyDirect; + case ArrayCopyReverse: return IntrinsicCallOp::ArrayCopyReverse; } assert(0); return IntrinsicCallOp::CharArrayCopy; // to keep compiler quiet @@ -894,13 +896,29 @@ IntrinsicCallInst * call = (IntrinsicCallInst *)inst; IntrinsicCallId callId = call->getIntrinsicId(); - cgInst = - instructionCallback.tau_callintr(inst->getNumSrcOperands()-2, // omit taus - genCallArgs(call,2), // omit taus - inst->getDst()->getType(), - convertIntrinsicId(callId), - getCGInst(tauNullChecked), - getCGInst(tauTypesChecked)); + if (callId == ArrayCopyDirect) + { + cgInst = + instructionCallback.arraycopy(inst->getNumSrcOperands()-2, // omit taus + genCallArgs(call,2) // omit taus + ); + } else if (callId == ArrayCopyReverse) + { + cgInst = + instructionCallback.arraycopyReverse(inst->getNumSrcOperands()-2, // omit taus + genCallArgs(call,2) // omit taus + ); + } else { + + cgInst = + instructionCallback.tau_callintr(inst->getNumSrcOperands()-2, // omit taus + genCallArgs(call,2), // omit taus + inst->getDst()->getType(), + convertIntrinsicId(callId), + getCGInst(tauNullChecked), + getCGInst(tauTypesChecked)); + } + } break; case Op_JitHelperCall: Index: vm/jitrino/src/optimizer/Inst.cpp =================================================================== --- vm/jitrino/src/optimizer/Inst.cpp (revision 476064) +++ vm/jitrino/src/optimizer/Inst.cpp (working copy) @@ -438,6 +438,10 @@ switch(intrinsicId) { case CharArrayCopy: os << "charArrayCopy"; break; + case ArrayCopyDirect: + os << "ArrayCopyDirect"; break; + case ArrayCopyReverse: + os << "ArrayCopyReverse"; break; default: assert(0); break; } Index: vm/jitrino/src/optimizer/Opcode.h =================================================================== --- vm/jitrino/src/optimizer/Opcode.h (revision 476064) +++ vm/jitrino/src/optimizer/Opcode.h (working copy) @@ -264,7 +264,9 @@ }; enum IntrinsicCallId { - CharArrayCopy + CharArrayCopy, + ArrayCopyDirect, + ArrayCopyReverse }; enum JitHelperCallId { Index: vm/jitrino/src/optimizer/memoryopt.cpp =================================================================== --- vm/jitrino/src/optimizer/memoryopt.cpp (revision 476064) +++ vm/jitrino/src/optimizer/memoryopt.cpp (working copy) @@ -624,6 +624,8 @@ IntrinsicCallId callId = calli->getIntrinsicId(); switch (callId) { case CharArrayCopy: + case ArrayCopyDirect: + case ArrayCopyReverse: { assert(calli->getNumSrcOperands() == 7); #ifndef NDEBUG @@ -638,6 +640,8 @@ Opnd *dstoffset = calli->getSrc(5); Opnd *length = calli->getSrc(6); + // effectXXXArrayElements actually does not depends on offset parameter + // so we do not need any special managing for the case of reverse copying thePass->effectReadArrayLength(n, i, srcarray); thePass->effectReadArrayElements(n, i, srcarray, srcoffset, length); thePass->effectReadArrayLength(n, i, dstarray); Index: vm/jitrino/src/translator/java/JavaByteCodeTranslator.h =================================================================== --- vm/jitrino/src/translator/java/JavaByteCodeTranslator.h (revision 476064) +++ vm/jitrino/src/translator/java/JavaByteCodeTranslator.h (working copy) @@ -317,8 +317,12 @@ void genInvokeStatic(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds,Type * returnType); void genMagic(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds,Type * returnType); + bool methodIsArraycopy(MethodDesc * methodDesc); + bool arraycopyOptimizable(MethodDesc * methodDesc, uint32 numArgs, Opnd ** srcOpnds); + bool genCharArrayCopy(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds, Type * returnType); - bool genArrayCopy(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds, Type * returnType); + bool genArrayCopyRepMove(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds); + bool genArrayCopy(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds); bool genMinMax(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds, Type * returnType); void newFallthroughBlock(); Index: vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp =================================================================== --- vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp (revision 476064) +++ vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp (working copy) @@ -2013,11 +2013,14 @@ returnType = typeManager.getNullObjectType(); } // - // Try to match to charArrayCopy + // Try some optimizations for System::arraycopy(...), Min, Max, Abs... // - if (translationFlags.genArrayCopy == true && - genArrayCopy(methodDesc,numArgs,srcOpnds,returnType)) { + if (translationFlags.genArrayCopyRepMove == true && + genArrayCopyRepMove(methodDesc,numArgs,srcOpnds)) { return; + } else if (translationFlags.genArrayCopy == true && + genArrayCopy(methodDesc,numArgs,srcOpnds)) { + return; } else if (translationFlags.genCharArrayCopy == true && genCharArrayCopy(methodDesc,numArgs,srcOpnds,returnType)) { return; @@ -2699,19 +2702,17 @@ } bool -JavaByteCodeTranslator::genArrayCopy(MethodDesc * methodDesc, - uint32 numArgs, - Opnd ** srcOpnds, - Type * returnType) { +JavaByteCodeTranslator::methodIsArraycopy(MethodDesc * methodDesc) { - // - // Check if method is java/lang/System.arraycopy - // (Object src, int srcPos, Object dst, int dstPos, int len) - // - if (strcmp(methodDesc->getName(),"arraycopy") != 0 || - strcmp(methodDesc->getParentType()->getName(),"java/lang/System") !=0) - return false; + return (strcmp(methodDesc->getName(),"arraycopy") == 0 && + strcmp(methodDesc->getParentType()->getName(),"java/lang/System") ==0); +} +bool +JavaByteCodeTranslator::arraycopyOptimizable(MethodDesc * methodDesc, + uint32 numArgs, + Opnd ** srcOpnds) { + // // an ArrayStoreException is thrown and the destination is not modified: // @@ -2725,19 +2726,14 @@ // assert(numArgs == 5); Opnd * src = srcOpnds[0]; - Opnd * srcPos = srcOpnds[1]; Type * srcType = src->getType(); - Type * srcPosType = srcPos->getType(); Opnd * dst = srcOpnds[2]; - Opnd * dstPos = srcOpnds[3]; Type * dstType = dst->getType(); - Type * dstPosType = dstPos->getType(); - Opnd * len = srcOpnds[4]; assert(srcType->isObject() && - srcPosType->isInt4() && + srcOpnds[1]->getType()->isInt4() && // 1 - srcPos dstType->isObject() && - dstPosType->isInt4() && - len->getType()->isInt4()); + srcOpnds[3]->getType()->isInt4() && // 3 - dstPos + srcOpnds[4]->getType()->isInt4()); // 4 - length bool throwsASE = false; bool srcIsArray = srcType->isArray(); @@ -2762,11 +2758,190 @@ throwsASE = ! typeManager.isSubClassOf(srcElemType->getVMTypeHandle(),dstElemType->getVMTypeHandle()); } if ( throwsASE ) - return false; // reject the inlining of System::arraycopy call + return false; + else + return true; +} +bool +JavaByteCodeTranslator::genArrayCopyRepMove(MethodDesc * methodDesc, + uint32 numArgs, + Opnd ** srcOpnds) { + + if( !methodIsArraycopy(methodDesc) || + !arraycopyOptimizable(methodDesc,numArgs,srcOpnds) ) + { + // reject the inlining of System::arraycopy call + return false; + } + if (Log::isEnabled()) { + Log::out() << "XXX array copy into 'rep move': "; + methodDesc->printFullName(Log::out()); + Log::out() << ::std::endl; + } + + assert(numArgs == 5); + Opnd * src = srcOpnds[0]; + Opnd * srcPos = srcOpnds[1]; + Type * srcPosType = srcPos->getType(); + Opnd * dst = srcOpnds[2]; + Opnd * dstPos = srcOpnds[3]; + Type * dstPosType = dstPos->getType(); + Opnd * len = srcOpnds[4]; + + // + // Generate exception condition checks: + // chknull src + // chknull dst + // cmpbr srcPos < 0, boundsException + // cmpbr dstPos < 0, boundsException + // cmpbr len < 0, boundsException + // srcEnd = add srcPos, len + // srcLen = src.length + // cmpbr srcEnd > srcLen, boundsException + // dstEnd = add dstPos, len + // dstLen = dst.length + // cmpbr dstEnd > dstLen, boundsException + // Skip trivial: + // cmpbr (src == dst) && (dstPos == srcPos), Exit + // Choose a direction: + // cmpbr (dstPos > srcPos) && (src == dst), Reverse + // + // Intrinsic calls will be codeselected into rep move instruction. + // Direct: + // IntrinsicCall id=ArrayCopyDirect + // goto Exit + // Reverse: + // srcPos = srcPos + len - 1 + // dstPos = dstPos + len - 1 + // IntrinsicCall id=ArrayCopyReverse + // goto Exit + // + // boundsException: + // chkbounds -1, src + // Exit: + // + Opnd *tauSrcNullChecked = irBuilder.genTauCheckNull(src); + Opnd *tauDstNullChecked = irBuilder.genTauCheckNull(dst); + Opnd *tauNullCheckedRefArgs = irBuilder.genTauAnd(tauSrcNullChecked,tauDstNullChecked); + + LabelInst * reverseCopying = irBuilder.createLabel(); + LabelInst * boundsException = irBuilder.createLabel(); + LabelInst * Exit = irBuilder.createLabel(); + Type * intType = typeManager.getInt32Type(); + Type * voidType = typeManager.getVoidType(); + + newFallthroughBlock(); + Opnd * zero = irBuilder.genLdConstant((int32)0); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,zero,srcPos); + + newFallthroughBlock(); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,zero,dstPos); + + newFallthroughBlock(); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,zero,len); + + Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No); + + newFallthroughBlock(); + Opnd * srcLen = irBuilder.genArrayLen(intType,Type::Int32,src); + Opnd * srcEnd = irBuilder.genAdd(intType,mod,srcPos,len); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,srcEnd,srcLen); + + newFallthroughBlock(); + Opnd * dstEnd = irBuilder.genAdd(intType,mod,dstPos,len); + Opnd * dstLen = irBuilder.genArrayLen(intType,Type::Int32,dst); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,dstEnd,dstLen); + + newFallthroughBlock(); + + // The case of same arrays and same positions + Opnd * diff = irBuilder.genCmp3(intType,Type::Int32,Cmp_GT,dstPos,srcPos); + Opnd * sameArrays = irBuilder.genCmp(intType,Type::IntPtr,Cmp_EQ,src,dst); + Opnd * zeroDiff = irBuilder.genCmp(intType,Type::Int32,Cmp_EQ,diff,zero); + Opnd * nothingToCopy = irBuilder.genAnd(intType,sameArrays,zeroDiff); + irBuilder.genBranch(Type::Int32,Cmp_GT,Exit,nothingToCopy,zero); + + newFallthroughBlock(); + + Opnd* tauTypesChecked = irBuilder.genTauSafe(); + + // Choosing direction + Opnd * dstIsGreater = irBuilder.genCmp(intType,Type::Int32,Cmp_GT,diff,zero); + Opnd * reverseCopy = irBuilder.genAnd(intType,sameArrays,dstIsGreater); + irBuilder.genBranch(Type::Int32,Cmp_GT,reverseCopying,reverseCopy,zero); + + newFallthroughBlock(); + + { // Direct Copying + irBuilder.genIntrinsicCall(ArrayCopyDirect,voidType, + tauNullCheckedRefArgs, + tauTypesChecked, + numArgs,srcOpnds); + irBuilder.genJump(Exit); + } // End of Direct Copying + + irBuilder.genLabel(reverseCopying); + cfgBuilder.genBlockAfterCurrent(reverseCopying); + { // Reverse Copying + + Opnd* minusone = irBuilder.genLdConstant((int32)-1); + Opnd* lastSrcIdx = irBuilder.genAdd(srcPosType,mod,srcEnd,minusone); + Opnd* lastDstIdx = irBuilder.genAdd(dstPosType,mod,dstEnd,minusone); + + Opnd** reverseArgs = new (memManager) Opnd*[numArgs]; + reverseArgs[0] = srcOpnds[0]; // src + reverseArgs[1] = lastSrcIdx; // srcPos+len-1 + reverseArgs[2] = srcOpnds[2]; // dst + reverseArgs[3] = lastDstIdx; // dstPos+len-1 + reverseArgs[4] = srcOpnds[4]; // len + // copy + irBuilder.genIntrinsicCall(ArrayCopyReverse,voidType, + tauNullCheckedRefArgs, + tauTypesChecked, + numArgs,reverseArgs); + irBuilder.genJump(Exit); + } // End of Reverse Copying + + irBuilder.genLabel(boundsException); + cfgBuilder.genBlockAfterCurrent(boundsException); + Opnd * minusOne = irBuilder.genLdConstant((int32)-1); + irBuilder.genTauCheckBounds(src,minusOne,tauSrcNullChecked); + + irBuilder.genLabel(Exit); + cfgBuilder.genBlockAfterCurrent(Exit); + + return true; +} + +bool +JavaByteCodeTranslator::genArrayCopy(MethodDesc * methodDesc, + uint32 numArgs, + Opnd ** srcOpnds) { + + if( !methodIsArraycopy(methodDesc) || + !arraycopyOptimizable(methodDesc,numArgs,srcOpnds) ) + { + // reject the inlining of System::arraycopy call + return false; + } + + if (Log::isEnabled()) { Log::out() << "XXX array copy: "; methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; } + + assert(numArgs == 5); + Opnd * src = srcOpnds[0]; + Type * srcType = src->getType(); + Opnd * srcPos = srcOpnds[1]; + Type * srcPosType = srcPos->getType(); + Opnd * dst = srcOpnds[2]; + Type * dstType = dst->getType(); + Opnd * dstPos = srcOpnds[3]; + Type * dstPosType = dstPos->getType(); + Opnd * len = srcOpnds[4]; + // // Generate exception condition checks: // chknull src Index: vm/jitrino/src/translator/TranslatorIntfc.h =================================================================== --- vm/jitrino/src/translator/TranslatorIntfc.h (revision 476064) +++ vm/jitrino/src/translator/TranslatorIntfc.h (working copy) @@ -49,18 +49,19 @@ // to select which byte code translator optimizations are done struct TranslatorFlags { - bool propValues : 1; // do value propagation - bool inlineMethods : 1; // do method inlining - bool guardedInlining : 1; // a step further for inlining - bool genCharArrayCopy : 1; // generate intrinsic calls to CharArrayCopy - bool genArrayCopy : 1; // inline java/lang/System::arraycopy call - bool onlyBalancedSync : 1; // treat all method synchronization as balanced - bool ignoreSync : 1; // do not generate monitor enter/exit instructions - bool syncAsEnterFence : 1; // implement monitor enter as enter fence and - bool newCatchHandling : 1; // use fix for catch handler ordering problem - bool genMinMaxAbs : 1; // gen min/max/abs opcodes instead of using select - bool genFMinMaxAbs : 1; // gen min/max/abs opcodes for floats - bool optArrayInit : 1; // skip array initializers from optimizations + bool propValues : 1; // do value propagation + bool inlineMethods : 1; // do method inlining + bool guardedInlining : 1; // a step further for inlining + bool genCharArrayCopy : 1; // generate intrinsic calls to CharArrayCopy + bool genArrayCopy : 1; // inline java/lang/System::arraycopy call as a copying loop + bool genArrayCopyRepMove: 1; // inline java/lang/System::arraycopy call as 'rep move' instruction + bool onlyBalancedSync : 1; // treat all method synchronization as balanced + bool ignoreSync : 1; // do not generate monitor enter/exit instructions + bool syncAsEnterFence : 1; // implement monitor enter as enter fence and + bool newCatchHandling : 1; // use fix for catch handler ordering problem + bool genMinMaxAbs : 1; // gen min/max/abs opcodes instead of using select + bool genFMinMaxAbs : 1; // gen min/max/abs opcodes for floats + bool optArrayInit : 1; // skip array initializers from optimizations Method_Table* inlineSkipTable; // do not inline these methods }; Index: vm/jitrino/src/translator/TranslatorIntfc.cpp =================================================================== --- vm/jitrino/src/translator/TranslatorIntfc.cpp (revision 476064) +++ vm/jitrino/src/translator/TranslatorIntfc.cpp (working copy) @@ -87,7 +87,8 @@ " propValues[={ON|off}] - propagate values during translation\n"\ " guardedInlining[={on|OFF}] - do guarded inlining during translation\n"\ " genCharArrayCopy[={on|off}] - generate intrinsic calls to char array copy\n"\ - " genArrayCopy[={ON|off}] - inline java/lang/System::arraycopy call\n"\ + " genArrayCopy[={ON|off}] - inline java/lang/System::arraycopy call as a copying loop\n"\ + " genArrayCopyRepMove[={ON|off}] - inline java/lang/System::arraycopy call as 'rep move' instruction\n"\ " balancedSync[={on|OFF}] - treat all synchronization as balanced\n"\ " ignoreSync[={on|OFF}] - do not generate synchronization\n"\ " syncAsEnterFence[={on|OFF}] - implement synchronization as monitor enter fence\n"\ @@ -115,7 +116,8 @@ flags.genCharArrayCopy = getBoolArg("genCharArrayCopy", false); flags.optArrayInit = getBoolArg("optArrayInit", true); #endif - flags.genArrayCopy = getBoolArg("genArrayCopy", true); + flags.genArrayCopy = getBoolArg("genArrayCopy", false); + flags.genArrayCopyRepMove = getBoolArg("genArrayCopyRepMove", true); flags.onlyBalancedSync = getBoolArg("balancedSync", false); flags.ignoreSync = getBoolArg("ignoreSync",false);