| /* |
| * 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 |
| * @version $Revision: 1.34.8.4.4.4 $ |
| */ |
| |
| #include "Stl.h" |
| #include "JavaByteCodeTranslator.h" |
| #include "JavaTranslator.h" |
| #include "Log.h" |
| #include "ExceptionInfo.h" |
| #include "simplifier.h" |
| #include "methodtable.h" |
| #include "open/bytecodes.h" |
| #include "irmanager.h" |
| #include "Jitrino.h" |
| #include "EMInterface.h" |
| #include "inliner.h" |
| #include "VMMagic.h" |
| |
| #include <assert.h> |
| #include <stdio.h> |
| |
| namespace Jitrino { |
| |
| static bool matchType(const char* candidate, const char* typeName) { |
| if (candidate[0]=='L') { |
| size_t typeLen = strlen(typeName); |
| size_t candLen = strlen(candidate); |
| bool res = typeLen+2 == candLen && !strncmp(typeName, candidate+1, typeLen); |
| return res; |
| } |
| return !strcmp(typeName, candidate); |
| } |
| |
| static Type* convertVMMagicType2HIR(TypeManager& tm, const char* name) { |
| assert(VMMagicUtils::isVMMagicClass(name)); |
| |
| if (matchType(name, "org/vmmagic/unboxed/Address") |
| //TODO: ObjectReference must have a ManagedPointer/Object type |
| || matchType(name, "org/vmmagic/unboxed/ObjectReference")) |
| { |
| return tm.getUnmanagedPtrType(tm.getInt8Type()); |
| } else if (matchType(name, "org/vmmagic/unboxed/Word") |
| || matchType(name, "org/vmmagic/unboxed/Offset") |
| || matchType(name, "org/vmmagic/unboxed/Extent")) |
| { |
| return tm.getUIntPtrType(); |
| } else if (matchType(name, "org/vmmagic/unboxed/WordArray") |
| || matchType(name, "org/vmmagic/unboxed/OffsetArray") |
| || matchType(name, "org/vmmagic/unboxed/ExtentArray") |
| || matchType(name, "org/vmmagic/unboxed/AddressArray") |
| || matchType(name, "org/vmmagic/unboxed/ObjectReferenceArray")) |
| { |
| #ifdef _EM64T_ |
| return tm.getArrayType(tm.getInt64Type(), false); |
| #else |
| return tm.getArrayType(tm.getInt32Type(), false); |
| #endif |
| } |
| assert(0); |
| return NULL; |
| } |
| |
| static Type* convertVMMagicType2HIR(TypeManager& tm, Type* type) { |
| if (!type->isObject() || !type->isNamedType() || type->isSystemObject()) { |
| return type; |
| } |
| const char* name = type->getName(); |
| return convertVMMagicType2HIR(tm, name); |
| } |
| |
| //vm helpers support |
| |
| static bool isVMHelperClass(const char* name) { |
| #ifdef _IPF_ |
| return false;//natives are not tested on IPF. |
| #else |
| bool res = !strcmp(name, VMHELPER_TYPE_NAME); |
| return res; |
| #endif |
| } |
| |
| |
| //----------------------------------------------------------------------------- |
| // JavaByteCodeTranslator constructors |
| //----------------------------------------------------------------------------- |
| // version for non-inlined methods |
| |
| JavaByteCodeTranslator::JavaByteCodeTranslator(CompilationInterface& ci, |
| MemoryManager& mm, |
| IRBuilder& irb, |
| ByteCodeParser& bcp, |
| MethodDesc& methodDesc, |
| TypeManager& typeManager, |
| JavaFlowGraphBuilder& cfg) |
| : |
| memManager(mm), |
| compilationInterface(ci), |
| methodToCompile(methodDesc), |
| parser(bcp), |
| typeManager(*irb.getTypeManager()), |
| irBuilder(irb), |
| translationFlags(*irb.getTranslatorFlags()), |
| cfgBuilder(cfg), |
| // CHECK ? for static sync methods must ensure at least one slot on stack for monitor enter/exit code |
| opndStack(mm,methodDesc.getMaxStack()+1), |
| returnOpnd(NULL), |
| returnNode(NULL), |
| inliningExceptionInfo(NULL), |
| prepass(memManager, |
| typeManager, |
| irBuilder.getInstFactory()->getMemManager(), |
| methodDesc, |
| ci, |
| NULL), |
| lockAddr(NULL), |
| oldLockValue(NULL), |
| jsrEntryMap(NULL), |
| retOffsets(mm), |
| jsrEntryOffsets(mm) |
| { |
| initJsrEntryMap(); |
| // create a prolog block |
| cfgBuilder.genBlock(irBuilder.genMethodEntryLabel(&methodDesc)); |
| initLocalVars(); |
| initArgs(); |
| CompilationContext* cc = CompilationContext::getCurrentContext(); |
| InliningContext* ic = cc->getInliningContext(); |
| // |
| // load actual parameters into formal parameters |
| // |
| for (U_32 i=0,j=0; i<numArgs; i++,j++) { |
| // |
| // for Java this is the same as a local var! |
| // |
| Opnd *arg; |
| if (i == 0 && methodToCompile.isStatic() == false) { |
| // |
| // for non-inlined, non-static methods, 'this' pointer should have non-null property set |
| // |
| arg = irBuilder.genArgDef(NonNullThisArg,argTypes[i]); |
| } else { |
| Type* type = argTypes[i]; |
| if (ic!=NULL) { |
| assert(ic->getNumArgs() == numArgs); |
| Type* newType = ic->getArgTypes()[i]; |
| if (newType->isObject()) { |
| assert(newType->isObject() == type->isObject()); |
| assert(newType->isNullObject() || newType->isUnresolvedType() || type->isUnresolvedType() |
| || newType->asObjectType()->isSubClassOf(type->asObjectType()) || newType->isSystemObject()); |
| type = newType; |
| } else { |
| //TODO: numX->numY auto conversion not tested |
| } |
| } |
| if (VMMagicUtils::isVMMagicClass(type->getName())) { |
| type = convertVMMagicType2HIR(typeManager, type); |
| } |
| arg = irBuilder.genArgDef(DefArgNoModifier,type); |
| } |
| JavaLabelPrepass::JavaVarType javaType = JavaLabelPrepass::getJavaType(argTypes[i]); |
| VarOpnd *var = getVarOpndStVar(javaType,j,arg); |
| // |
| // longs & doubles take up 2 slots |
| // |
| if (javaType==JavaLabelPrepass::L || javaType==JavaLabelPrepass::D) |
| j++; |
| if (var != NULL) |
| irBuilder.genStVar(var,arg); |
| stateInfo->stack[j].vars = new (memManager) SlotVar(prepass.getVarInc(0, j)); |
| } |
| // check for synchronized methods |
| if (methodToCompile.isSynchronized()) { |
| if (methodToCompile.isStatic()) { |
| //irBuilder.genTypeMonitorEnter(methodToCompile.getParentType()); |
| Opnd* classObjectOpnd = irBuilder.genGetClassObj((ObjectType*) methodToCompile.getParentType()); |
| pushOpnd(classObjectOpnd); |
| genMethodMonitorEnter(); |
| } else { |
| genLdVar(0,JavaLabelPrepass::A); |
| genMethodMonitorEnter(); |
| } |
| } |
| |
| if(!prepass.allExceptionTypesResolved()) { |
| unsigned problemToken = prepass.getProblemTypeToken(); |
| assert(problemToken != MAX_UINT32); |
| linkingException(problemToken,OPCODE_CHECKCAST); // CHECKCAST is suitable here |
| noNeedToParse = true; |
| } |
| } |
| |
| |
| //----------------------------------------------------------------------------- |
| // initialization helpers |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::initJsrEntryMap() |
| { |
| MemoryManager& ir_mem_manager = irBuilder.getIRManager()->getMemoryManager(); |
| jsrEntryMap = new (ir_mem_manager) JsrEntryInstToRetInstMap(ir_mem_manager); |
| } |
| |
| void |
| JavaByteCodeTranslator::initLocalVars() { |
| // |
| // perform label prepass in this method |
| // |
| parser.parse(&prepass); |
| prepass.parseDone(); |
| prepassVisited = prepass.bytecodevisited; |
| moreThanOneReturn = false; |
| jumpToTheEnd = false; |
| lastInstructionWasABranch = false; |
| |
| // compute number of labels |
| numLabels = prepass.getNumLabels(); |
| labels = new (memManager) LabelInst*[numLabels+1]; |
| irBuilder.createLabels(numLabels,labels); |
| |
| nextLabel = 0; |
| resultOpnd = NULL; |
| |
| numVars = methodToCompile.getNumVars(); |
| numStackVars = prepass.getStateTable()->getMaxStackOverflow()-numVars; |
| stateInfo = &prepass.stateInfo; |
| for (U_32 k=0; k < numVars+numStackVars; k++) { |
| struct StateInfo::SlotInfo *slot = &stateInfo->stack[k]; |
| slot->type = NULL; |
| slot->slotFlags = 0; |
| slot->vars = NULL; |
| } |
| stateInfo->stackDepth = numVars; |
| javaTypeMap[JavaLabelPrepass::I] = typeManager.getInt32Type(); |
| javaTypeMap[JavaLabelPrepass::L] = typeManager.getInt64Type(); |
| javaTypeMap[JavaLabelPrepass::F] = typeManager.getSingleType(); |
| javaTypeMap[JavaLabelPrepass::D] = typeManager.getDoubleType(); |
| javaTypeMap[JavaLabelPrepass::A] = typeManager.getSystemObjectType(); |
| javaTypeMap[JavaLabelPrepass::RET] = typeManager.getIntPtrType(); |
| prepass.createMultipleDefVarOpnds(&irBuilder); |
| |
| } |
| |
| void |
| JavaByteCodeTranslator::initArgs() { |
| // incoming argument and return value information |
| numArgs = methodToCompile.getNumParams(); |
| retType = methodToCompile.getReturnType(); |
| argTypes = new (memManager) Type*[numArgs]; |
| args = new (memManager) Opnd*[numArgs]; |
| for (uint16 i=0; i<numArgs; i++) { |
| Type* argType = methodToCompile.getParamType(i); |
| assert(!(typeManager.isLazyResolutionMode() && argType==NULL)); |
| // argType == NULL if it fails to be resolved. Respective exception |
| // will be thrown at the point of usage |
| argTypes[i] = argType != NULL ? argType : typeManager.getNullObjectType(); |
| } |
| } |
| |
| //----------------------------------------------------------------------------- |
| // variable management helpers |
| //----------------------------------------------------------------------------- |
| // returns either VarOpnd or Opnd. If returning is operand, do not generate the LdVar, only |
| // push the operand |
| // |
| Opnd* |
| JavaByteCodeTranslator::getVarOpndLdVar(JavaLabelPrepass::JavaVarType javaType,U_32 index) { |
| if (index >= numVars+numStackVars) |
| // error: invalid local variable id |
| invalid(); |
| struct StateInfo::SlotInfo slot = stateInfo->stack[index]; |
| assert(slot.vars); |
| Opnd* var = slot.vars->getVarIncarnation()->getOrCreateOpnd(&irBuilder); |
| return var; |
| } |
| |
| // returns either VarOpnd or null. If null, does not generate the StVar |
| |
| VarOpnd* |
| JavaByteCodeTranslator::getVarOpndStVar(JavaLabelPrepass::JavaVarType javaType, |
| U_32 index, |
| Opnd* opnd) { |
| if (index >= numVars+numStackVars) |
| // error: invalid local variable id |
| invalid(); |
| VariableIncarnation* varInc = prepass.getVarInc(currentOffset, index); |
| Opnd* var = NULL; |
| StateInfo::SlotInfo* slot = NULL; |
| slot = &stateInfo->stack[index]; |
| if(varInc) { |
| slot->vars = new (memManager) SlotVar(varInc); |
| var = varInc->getOpnd(); |
| } |
| |
| if (var) { |
| assert(var->isVarOpnd()); |
| return var->asVarOpnd(); |
| } else { |
| slot->type = typeManager.toInternalType(opnd->getType()); |
| slot->slotFlags = 0; |
| if (isNonNullOpnd(opnd)) |
| StateInfo::setNonNull(slot); |
| if (isExactTypeOpnd(opnd)) |
| StateInfo::setExactType(slot); |
| varInc->setTmpOpnd(opnd); |
| return NULL; |
| } |
| } |
| |
| //----------------------------------------------------------------------------- |
| // operand stack manipulation helpers |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::pushOpnd(Opnd* opnd) { |
| assert(opnd->getInst()); |
| opndStack.push(opnd); |
| } |
| |
| Opnd* |
| JavaByteCodeTranslator::topOpnd() { |
| return opndStack.top(); |
| } |
| |
| Opnd* |
| JavaByteCodeTranslator::popOpnd() { |
| Opnd *top = opndStack.pop(); |
| setStackOpndAliveOpnd(top,true); |
| return top; |
| } |
| |
| Opnd* |
| JavaByteCodeTranslator::popOpndStVar() { |
| return opndStack.pop(); |
| } |
| |
| // |
| // Called at the end of each basic block to empty out the operand stack |
| // |
| void |
| JavaByteCodeTranslator::checkStack() { |
| int numElems = opndStack.getNumElems(); |
| for (int i = numElems-1; i >= 0; i--) { |
| Opnd* opnd = popOpndStVar(); |
| JavaLabelPrepass::JavaVarType javaType = |
| JavaLabelPrepass::getJavaType(opnd->getType()); |
| |
| VarOpnd* var = getVarOpndStVar(javaType,(uint16)(numVars+i),opnd); |
| // simple optimization |
| if(var != NULL) { |
| Inst* srcInst = opnd->getInst(); |
| assert(srcInst); |
| if ((srcInst->getOpcode() != Op_LdVar) || |
| (srcInst->getSrc(0)->getId() != var->getId())) { |
| irBuilder.genStVar(var,opnd); |
| setStackOpndAliveOpnd(opnd,true); |
| } else { |
| } |
| } |
| } |
| } |
| //----------------------------------------------------------------------------- |
| // constant pool resolution helpers |
| //----------------------------------------------------------------------------- |
| |
| const char* |
| JavaByteCodeTranslator::methodSignatureString(U_32 cpIndex) { |
| return compilationInterface.getSignatureString(&methodToCompile,cpIndex); |
| } |
| |
| U_32 |
| JavaByteCodeTranslator::labelId(U_32 offset) { |
| U_32 labelId = prepass.getLabelId(offset); |
| if (labelId == (U_32) -1) |
| jitrino_assert(0); |
| return labelId; |
| } |
| |
| //----------------------------------------------------------------------------- |
| // misc JavaByteCodeParserCallback methods |
| //----------------------------------------------------------------------------- |
| |
| // called when invalid byte code is encountered |
| void |
| JavaByteCodeTranslator::invalid() { |
| jitrino_assert(0); |
| } |
| |
| // called when an error occurs during the byte code parsing |
| void |
| JavaByteCodeTranslator::parseError() { |
| jitrino_assert(0); |
| } |
| |
| void |
| JavaByteCodeTranslator::offset(U_32 offset) { |
| |
| // set bc offset in ir builder |
| irBuilder.setBcOffset(offset); |
| if (prepass.isLabel(offset) == false) |
| return; |
| if (prepassVisited && prepassVisited->getBit(offset) == false) { |
| getNextLabelId(); // skip this DEAD byte code |
| return; |
| } |
| |
| // finish the previous basic block, if any work was required |
| if (!lastInstructionWasABranch) { |
| checkStack(); |
| } |
| lastInstructionWasABranch = false; |
| |
| // start with the current basic block |
| StateInfo* state = prepass.stateTable->getStateInfo(offset); |
| stateInfo->flags = state->flags; |
| stateInfo->stackDepth = state->stackDepth; |
| stateInfo->exceptionInfo = state->exceptionInfo; |
| for(unsigned i=0; i<state->stackDepth; ++i) |
| stateInfo->stack[i] = state->stack[i]; |
| assert(stateInfo != NULL); |
| Type* handlerExceptionType = NULL; |
| U_32 lblId = getNextLabelId(); |
| LabelInst* labelInst = getLabel(lblId); |
| |
| ::std::vector<LabelInst*> catchLabels; |
| |
| bool isCatchHandler = false; |
| for (ExceptionInfo* exceptionInfo = stateInfo->getExceptionInfo(); |
| exceptionInfo != NULL; |
| exceptionInfo = exceptionInfo->getNextExceptionInfoAtOffset()) { |
| if (exceptionInfo->isCatchBlock()) { |
| CatchBlock* catchBlock = (CatchBlock*)exceptionInfo; |
| CatchHandler *first = ((CatchBlock*)exceptionInfo)->getHandlers(); |
| if (Log::isEnabled()) { |
| Log::out() << "TRY REGION " << (int)exceptionInfo->getBeginOffset() |
| << " " << (int)exceptionInfo->getEndOffset() << ::std::endl; |
| for (; first != NULL; first = first->getNextHandler()) { |
| Log::out() << " handler " << (int)first->getBeginOffset() << ::std::endl; |
| } |
| } |
| if (catchBlock->getLabelInst() == NULL) { |
| Node *dispatchNode = cfgBuilder.createDispatchNode(); |
| catchBlock->setLabelInst((LabelInst*)dispatchNode->getFirstInst()); |
| ((LabelInst*)dispatchNode->getFirstInst())->setState(catchBlock); |
| } |
| if (labelInst->getState() == NULL) |
| labelInst->setState(catchBlock); |
| if(Log::isEnabled()) { |
| Log::out() << "LABEL "; labelInst->print(Log::out()); Log::out() << labelInst->getState(); |
| Log::out() << "CATCH ";catchBlock->getLabelInst()->print(Log::out()); Log::out() << ::std::endl; |
| } |
| } else if (exceptionInfo->isCatchHandler()) { |
| // catch handler block |
| isCatchHandler = true; |
| CatchHandler* handler = (CatchHandler*)exceptionInfo; |
| if (Log::isEnabled()) Log::out() << "CATCH REGION " << (int)exceptionInfo->getBeginOffset() |
| << " " << (int)exceptionInfo->getEndOffset() << ::std::endl; |
| handlerExceptionType = (handlerExceptionType == NULL) ? |
| handler->getExceptionType() : |
| typeManager.getCommonObjectType((ObjectType*) handlerExceptionType, (ObjectType*) handler->getExceptionType()); |
| LabelInst *oldLabel = labelInst; |
| labelInst = irBuilder.getInstFactory()->makeCatchLabel( |
| handler->getExceptionOrder(), |
| handler->getExceptionType()); |
| labelInst->setBCOffset((uint16)exceptionInfo->getBeginOffset()); |
| catchLabels.push_back(labelInst); |
| labelInst->setState(oldLabel->getState()); |
| exceptionInfo->setLabelInst(labelInst); |
| if(Log::isEnabled()) { |
| Log::out() << "LABEL "; labelInst->print(Log::out()); Log::out() << labelInst->getState(); |
| Log::out() << "CATCH "; handler->getLabelInst()->print(Log::out()); Log::out() << ::std::endl; |
| } |
| } else {jitrino_assert(0);} // only catch blocks should occur in Java |
| } |
| // generate the label instruction |
| if(!catchLabels.empty()) { |
| for(::std::vector<LabelInst*>::iterator iter = catchLabels.begin(); iter != catchLabels.end(); ++iter) { |
| LabelInst* catchLabel = *iter; |
| irBuilder.genLabel(catchLabel); |
| cfgBuilder.genBlock(catchLabel); |
| } |
| LabelInst* handlerLabel= getLabel(lblId); |
| assert(!handlerLabel->isCatchLabel()); |
| handlerLabel->setState(labelInst->getState()); |
| irBuilder.genLabel(handlerLabel); |
| cfgBuilder.genBlock(handlerLabel); |
| } else { |
| if (stateInfo->isFallThroughLabel()) { |
| irBuilder.genFallThroughLabel(labelInst); |
| } else { |
| irBuilder.genLabel(labelInst); |
| // empty out the stack operand |
| opndStack.makeEmpty(); |
| } |
| cfgBuilder.genBlock(labelInst); |
| } |
| |
| if (isCatchHandler) { |
| // for catch handler blocks, generate the catch instruction |
| assert(stateInfo->isCatchLabel()); |
| assert(1 == stateInfo->stackDepth - numVars); |
| assert(stateInfo->stack[numVars].type == handlerExceptionType); |
| pushOpnd(irBuilder.genCatch(stateInfo->stack[numVars].type)); |
| } else { |
| // |
| // Load var operands where current basic block begins |
| // |
| for (U_32 k=numVars; k < (U_32)stateInfo->stackDepth; k++) { |
| if(Log::isEnabled()) { |
| Log::out() << "STACK ";StateInfo::print(stateInfo->stack[k], Log::out());Log::out() << ::std::endl; |
| } |
| genLdVar(k,prepass.getJavaType(stateInfo->stack[k].type)); |
| } |
| } |
| if (stateInfo->isSubroutineEntry()) { |
| pushOpnd(irBuilder.genSaveRet()); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::offset_done(U_32 offset) { |
| if (prepass.isSubroutineEntry(offset) ) { |
| jsrEntryOffsets[offset] = irBuilder.getLastGeneratedInst(); |
| } |
| } |
| |
| // |
| // called when byte code parsing is done |
| // |
| void |
| JavaByteCodeTranslator::parseDone() |
| { |
| OffsetToInstMap::const_iterator ret_i, ret_e; |
| for (ret_i = retOffsets.begin(), ret_e = retOffsets.end(); ret_i != ret_e; ++ret_i) { |
| U_32 ret_offset = ret_i->first; |
| Inst* ret_inst = ret_i->second; |
| JavaLabelPrepass::RetToSubEntryMap* ret_to_entry_map = prepass.getRetToSubEntryMapPtr(); |
| JavaLabelPrepass::RetToSubEntryMap::const_iterator sub_i = ret_to_entry_map->find(ret_offset); |
| // |
| // jsr target should be found for each ret inst |
| // |
| assert(sub_i != ret_to_entry_map->end()); |
| U_32 entry_offset = sub_i->second; |
| OffsetToInstMap::const_iterator entry_inst_i = jsrEntryOffsets.find(entry_offset); |
| assert(entry_inst_i != jsrEntryOffsets.end()); |
| Inst* entry_inst = entry_inst_i->second; |
| 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; |
| } |
| |
| //----------------------------------------------------------------------------- |
| // byte code callbacks |
| //----------------------------------------------------------------------------- |
| |
| void JavaByteCodeTranslator::nop() {} |
| |
| //----------------------------------------------------------------------------- |
| // load constant byte codes |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::aconst_null() { |
| pushOpnd(irBuilder.genLdNull()); |
| } |
| void |
| JavaByteCodeTranslator::iconst(I_32 val) { |
| pushOpnd(irBuilder.genLdConstant(val)); |
| } |
| void |
| JavaByteCodeTranslator::lconst(int64 val) { |
| pushOpnd(irBuilder.genLdConstant(val)); |
| } |
| void |
| JavaByteCodeTranslator::fconst(float val) { |
| pushOpnd(irBuilder.genLdConstant(val)); |
| } |
| void |
| JavaByteCodeTranslator::dconst(double val){ |
| pushOpnd(irBuilder.genLdConstant(val)); |
| } |
| void |
| JavaByteCodeTranslator::bipush(I_8 val) { |
| pushOpnd(irBuilder.genLdConstant((I_32)val)); |
| } |
| void |
| JavaByteCodeTranslator::sipush(int16 val) { |
| pushOpnd(irBuilder.genLdConstant((I_32)val)); |
| } |
| void |
| JavaByteCodeTranslator::ldc(U_32 constPoolIndex) { |
| // load 32-bit quantity or string from constant pool |
| Type* constantType = |
| compilationInterface.getConstantType(&methodToCompile,constPoolIndex); |
| Opnd* opnd = NULL; |
| if (constantType->isSystemString()) { |
| opnd = irBuilder.genLdRef(&methodToCompile,constPoolIndex,constantType); |
| } else if (constantType->isSystemClass()) { |
| NamedType *literalType = compilationInterface.getNamedType(methodToCompile.getParentHandle(), constPoolIndex); |
| if (!typeManager.isLazyResolutionMode() && literalType->isUnresolvedType()) { |
| linkingException(constPoolIndex, OPCODE_LDC); |
| } |
| opnd = irBuilder.genLdRef(&methodToCompile,constPoolIndex,constantType); |
| } else { |
| const void* constantAddress = |
| compilationInterface.getConstantValue(&methodToCompile,constPoolIndex); |
| if (constantType->isInt4()) { |
| I_32 value = *(I_32*)constantAddress; |
| opnd = irBuilder.genLdConstant(value); |
| } else if (constantType->isSingle()) { |
| float value = *(float*)constantAddress; |
| opnd = irBuilder.genLdConstant((float)value); |
| } else { |
| // Invalid type! |
| jitrino_assert(0); |
| } |
| } |
| pushOpnd(opnd); |
| } |
| |
| void |
| JavaByteCodeTranslator::ldc2(U_32 constPoolIndex) { |
| // load 64-bit quantity from constant pool |
| Type* constantType = |
| compilationInterface.getConstantType(&methodToCompile,constPoolIndex); |
| |
| const void* constantAddress = |
| compilationInterface.getConstantValue(&methodToCompile,constPoolIndex); |
| Opnd *opnd = NULL; |
| if (constantType->isInt8()) { |
| int64 value = *(int64*)constantAddress; |
| opnd = irBuilder.genLdConstant((int64)value); |
| } else if (constantType->isDouble()) { |
| double value = *(double*)constantAddress; |
| opnd = irBuilder.genLdConstant((double)value); |
| } else { |
| // Invalid type! |
| jitrino_assert(0); |
| } |
| pushOpnd(opnd); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // variable access byte codes |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::iload(uint16 varIndex) { |
| genLdVar(varIndex,JavaLabelPrepass::I); |
| } |
| void |
| JavaByteCodeTranslator::lload(uint16 varIndex) { |
| genLdVar(varIndex,JavaLabelPrepass::L); |
| } |
| void |
| JavaByteCodeTranslator::fload(uint16 varIndex) { |
| genLdVar(varIndex,JavaLabelPrepass::F); |
| } |
| void |
| JavaByteCodeTranslator::dload(uint16 varIndex) { |
| genLdVar(varIndex,JavaLabelPrepass::D); |
| } |
| void |
| JavaByteCodeTranslator::aload(uint16 varIndex) { |
| genLdVar(varIndex,JavaLabelPrepass::A); |
| } |
| void |
| JavaByteCodeTranslator::istore(uint16 varIndex,U_32 off) { |
| genStVar(varIndex,JavaLabelPrepass::I); |
| } |
| void |
| JavaByteCodeTranslator::lstore(uint16 varIndex,U_32 off) { |
| genStVar(varIndex,JavaLabelPrepass::L); |
| } |
| void |
| JavaByteCodeTranslator::fstore(uint16 varIndex,U_32 off) { |
| genStVar(varIndex,JavaLabelPrepass::F); |
| } |
| void |
| JavaByteCodeTranslator::dstore(uint16 varIndex,U_32 off) { |
| genStVar(varIndex,JavaLabelPrepass::D); |
| } |
| void |
| JavaByteCodeTranslator::astore(uint16 varIndex,U_32 off) { |
| genTypeStVar(varIndex); |
| } |
| //----------------------------------------------------------------------------- |
| // field access byte codes |
| //----------------------------------------------------------------------------- |
| Type* |
| JavaByteCodeTranslator::getFieldType(FieldDesc* field, U_32 constPoolIndex) { |
| Type* fieldType = field->getFieldType(); |
| if (!fieldType) { |
| // some problem with fieldType class handle. Let's try the constant_pool. |
| // (For example if the field type class is deleted, the field is beeing resolved successfully |
| // but field->getFieldType() returns NULL in this case) |
| fieldType = compilationInterface.getFieldType(methodToCompile.getParentHandle(),constPoolIndex); |
| } |
| return fieldType; |
| } |
| |
| |
| void |
| JavaByteCodeTranslator::getstatic(U_32 constPoolIndex) { |
| FieldDesc *field = compilationInterface.getStaticField(methodToCompile.getParentHandle(), constPoolIndex, false); |
| if (field && field->isStatic()) { |
| bool fieldValueInlined = false; |
| Type* fieldType = field->getFieldType(); |
| assert(fieldType); |
| bool fieldIsMagic = VMMagicUtils::isVMMagicClass(fieldType->getName()); |
| if (fieldIsMagic) { |
| fieldType = convertVMMagicType2HIR(typeManager, fieldType); |
| } |
| if (field->isInitOnly() && !field->getParentType()->needsInitialization()) { |
| //the final static field of the initialized class |
| if (field->getFieldType()->isNumeric() || field->getFieldType()->isBoolean() || fieldIsMagic) { |
| Opnd* constVal = NULL; |
| void* fieldAddr = field->getAddress(); |
| switch(fieldType->tag) { |
| case Type::Int8 : constVal=irBuilder.genLdConstant(*(I_8*)fieldAddr);break; |
| case Type::Int16: constVal=irBuilder.genLdConstant(*(int16*)fieldAddr);break; |
| case Type::Char : constVal=irBuilder.genLdConstant(*(uint16*)fieldAddr);break; |
| case Type::Int32: constVal=irBuilder.genLdConstant(*(I_32*)fieldAddr);break; |
| case Type::Int64: constVal=irBuilder.genLdConstant(*(int64*)fieldAddr);break; |
| case Type::Single: constVal=irBuilder.genLdConstant(*(float*)fieldAddr);break; |
| case Type::Double: constVal=irBuilder.genLdConstant(*(double*)fieldAddr);break; |
| case Type::Boolean: constVal=irBuilder.genLdConstant(*(bool*)fieldAddr);break; |
| case Type::UnmanagedPtr: assert(fieldIsMagic); |
| #ifdef _IA32_ |
| constVal=irBuilder.genLdConstant(*(I_32*)fieldAddr); |
| #else |
| assert(sizeof(void*)==8); |
| constVal=irBuilder.genLdConstant(*(int64*)fieldAddr); |
| #endif |
| break; |
| default: assert(0); //?? |
| } |
| if (constVal != NULL) { |
| pushOpnd(constVal); |
| fieldValueInlined = true; |
| } |
| } |
| } |
| if (!fieldValueInlined){ |
| pushOpnd(irBuilder.genLdStatic(fieldType, field)); |
| } |
| } else { |
| //field is not resolved or not static |
| if (!typeManager.isLazyResolutionMode()) { |
| // generate helper call for throwing respective exception |
| linkingException(constPoolIndex, OPCODE_GETSTATIC); |
| } |
| const char* fieldTypeName = CompilationInterface::getFieldSignature(methodToCompile.getParentHandle(), constPoolIndex); |
| bool fieldIsMagic = VMMagicUtils::isVMMagicClass(fieldTypeName); |
| Type* fieldType = fieldIsMagic ? convertVMMagicType2HIR(typeManager, fieldTypeName) |
| : compilationInterface.getFieldType(methodToCompile.getParentHandle(), constPoolIndex); |
| Opnd* res = irBuilder.genLdStaticWithResolve(fieldType, methodToCompile.getParentType()->asObjectType(), constPoolIndex); |
| pushOpnd(res); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::putstatic(U_32 constPoolIndex) { |
| FieldDesc *field = compilationInterface.getStaticField(methodToCompile.getParentHandle(), constPoolIndex, true); |
| if (field && field->isStatic()) { |
| Type* fieldType = getFieldType(field,constPoolIndex); |
| assert(fieldType); |
| bool fieldIsMagic = VMMagicUtils::isVMMagicClass(fieldType->getName()); |
| if (fieldIsMagic) { |
| fieldType = convertVMMagicType2HIR(typeManager, fieldType); |
| } |
| irBuilder.genStStatic(fieldType,field,popOpnd()); |
| } else { |
| //field is not resolved or not static |
| if (!typeManager.isLazyResolutionMode()) { |
| // generate helper call for throwing respective exception |
| linkingException(constPoolIndex, OPCODE_PUTSTATIC); |
| } |
| const char* fieldTypeName = CompilationInterface::getFieldSignature(methodToCompile.getParentHandle(), constPoolIndex); |
| bool fieldIsMagic = VMMagicUtils::isVMMagicClass(fieldTypeName); |
| Type* fieldType = fieldIsMagic ? convertVMMagicType2HIR(typeManager, fieldTypeName) |
| : compilationInterface.getFieldType(methodToCompile.getParentHandle(), constPoolIndex); |
| Opnd* value = popOpnd(); |
| irBuilder.genStStaticWithResolve(fieldType, methodToCompile.getParentType()->asObjectType(), constPoolIndex, value); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::getfield(U_32 constPoolIndex) { |
| FieldDesc *field = compilationInterface.getNonStaticField(methodToCompile.getParentHandle(), constPoolIndex, false); |
| if (field && !field->isStatic()) { |
| Type* fieldType = getFieldType(field, constPoolIndex); |
| if (VMMagicUtils::isVMMagicClass(fieldType->getName())) { |
| fieldType = convertVMMagicType2HIR(typeManager, fieldType); |
| } |
| pushOpnd(irBuilder.genLdField(fieldType,popOpnd(),field)); |
| } else { |
| if (!typeManager.isLazyResolutionMode()) { |
| // generate helper call for throwing respective exception |
| linkingException(constPoolIndex, OPCODE_GETFIELD); |
| } |
| Type* fieldType = compilationInterface.getFieldType(methodToCompile.getParentHandle(), constPoolIndex); |
| if (VMMagicUtils::isVMMagicClass(fieldType->getName())) { |
| fieldType = convertVMMagicType2HIR(typeManager, fieldType); |
| } |
| Opnd* base = popOpnd(); |
| Opnd* res = irBuilder.genLdFieldWithResolve(fieldType, base, methodToCompile.getParentType()->asObjectType(), constPoolIndex); |
| pushOpnd(res); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::putfield(U_32 constPoolIndex) { |
| FieldDesc *field = compilationInterface.getNonStaticField(methodToCompile.getParentHandle(), constPoolIndex, true); |
| if (field && !field->isStatic()) { |
| Type* fieldType = getFieldType(field,constPoolIndex); |
| assert(fieldType); |
| if (VMMagicUtils::isVMMagicClass(fieldType->getName())) { |
| fieldType = convertVMMagicType2HIR(typeManager, fieldType); |
| } |
| |
| Opnd* value = popOpnd(); |
| Opnd* ref = popOpnd(); |
| irBuilder.genStField(fieldType,ref,field,value); |
| } else { |
| if (!typeManager.isLazyResolutionMode()) { |
| // generate helper call for throwing respective exception |
| linkingException(constPoolIndex, OPCODE_PUTFIELD); |
| } |
| Type* type = compilationInterface.getFieldType(methodToCompile.getParentHandle(), constPoolIndex); |
| Opnd* value = popOpnd(); |
| Opnd* base = popOpnd(); |
| irBuilder.genStFieldWithResolve(type, base, methodToCompile.getParentType()->asObjectType(), constPoolIndex, value); |
| } |
| } |
| //----------------------------------------------------------------------------- |
| // array access byte codes |
| //----------------------------------------------------------------------------- |
| void JavaByteCodeTranslator::iaload() { |
| genArrayLoad(typeManager.getInt32Type()); |
| } |
| void JavaByteCodeTranslator::laload() { |
| genArrayLoad(typeManager.getInt64Type()); |
| } |
| void JavaByteCodeTranslator::faload() { |
| genArrayLoad(typeManager.getSingleType()); |
| } |
| void JavaByteCodeTranslator::daload() { |
| genArrayLoad(typeManager.getDoubleType()); |
| } |
| void JavaByteCodeTranslator::aaload() { |
| genTypeArrayLoad(); |
| } |
| void JavaByteCodeTranslator::baload() { |
| genArrayLoad(typeManager.getInt8Type()); |
| } |
| void JavaByteCodeTranslator::caload() { |
| genArrayLoad(typeManager.getCharType()); |
| } |
| void JavaByteCodeTranslator::saload() { |
| genArrayLoad(typeManager.getInt16Type()); |
| } |
| void JavaByteCodeTranslator::iastore() { |
| genArrayStore(typeManager.getInt32Type()); |
| } |
| void JavaByteCodeTranslator::lastore() { |
| genArrayStore(typeManager.getInt64Type()); |
| } |
| void JavaByteCodeTranslator::fastore() { |
| genArrayStore(typeManager.getSingleType()); |
| } |
| void JavaByteCodeTranslator::dastore() { |
| genArrayStore(typeManager.getDoubleType()); |
| } |
| void JavaByteCodeTranslator::aastore() { |
| genTypeArrayStore(); |
| } |
| void JavaByteCodeTranslator::bastore() { |
| genArrayStore(typeManager.getInt8Type()); |
| } |
| void JavaByteCodeTranslator::castore() { |
| genArrayStore(typeManager.getCharType()); |
| } |
| void JavaByteCodeTranslator::sastore() { |
| genArrayStore(typeManager.getInt16Type()); |
| } |
| //----------------------------------------------------------------------------- |
| // stack manipulation byte codes (pops, dups & exchanges) |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::pop() {popOpnd();} |
| |
| bool |
| isCategory2(Opnd* opnd) { |
| return (opnd->getType()->isInt8() || opnd->getType()->isDouble()); |
| } |
| |
| void |
| JavaByteCodeTranslator::pop2() { |
| Opnd* opnd = popOpnd(); |
| if (isCategory2(opnd)) |
| return; |
| popOpnd(); |
| } |
| |
| void |
| JavaByteCodeTranslator::dup() { |
| pushOpnd(topOpnd()); |
| } |
| |
| void |
| JavaByteCodeTranslator::dup_x1() { |
| Opnd* opnd1 = popOpnd(); |
| Opnd* opnd2 = popOpnd(); |
| pushOpnd(opnd1); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } |
| |
| void |
| JavaByteCodeTranslator::dup_x2() { |
| Opnd* opnd1 = popOpnd(); |
| Opnd* opnd2 = popOpnd(); |
| if (isCategory2(opnd2)) { |
| pushOpnd(opnd1); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| return; |
| } |
| Opnd* opnd3 = popOpnd(); |
| pushOpnd(opnd1); |
| pushOpnd(opnd3); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } |
| |
| void |
| JavaByteCodeTranslator::dup2() { |
| Opnd* opnd1 = popOpnd(); |
| if (isCategory2(opnd1)) { |
| pushOpnd(opnd1); |
| pushOpnd(opnd1); |
| return; |
| } |
| Opnd* opnd2 = popOpnd(); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } |
| |
| void |
| JavaByteCodeTranslator::dup2_x1() { |
| Opnd* opnd1 = popOpnd(); |
| Opnd* opnd2 = popOpnd(); |
| if (isCategory2(opnd1)) { |
| // opnd1 is a category 2 instruction |
| pushOpnd(opnd1); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } else { |
| // opnd1 is a category 1 instruction |
| Opnd* opnd3 = popOpnd(); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| pushOpnd(opnd3); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::dup2_x2() { |
| Opnd* opnd1 = popOpnd(); |
| Opnd* opnd2 = popOpnd(); |
| if (isCategory2(opnd1)) { |
| // opnd1 is category 2 |
| if (isCategory2(opnd2)) { |
| pushOpnd(opnd1); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } else { |
| // opnd2 is category 1 |
| Opnd* opnd3 = popOpnd(); |
| assert(isCategory2(opnd3) == false); |
| pushOpnd(opnd1); |
| pushOpnd(opnd3); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } |
| } else { |
| assert(isCategory2(opnd2) == false); |
| // both opnd1 & opnd2 are category 1 |
| Opnd* opnd3 = popOpnd(); |
| if (isCategory2(opnd3)) { |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| pushOpnd(opnd3); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } else { |
| // opnd1, opnd2, opnd3 all are category 1 |
| Opnd* opnd4 = popOpnd(); |
| assert(isCategory2(opnd4) == false); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| pushOpnd(opnd4); |
| pushOpnd(opnd3); |
| pushOpnd(opnd2); |
| pushOpnd(opnd1); |
| } |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::swap() { |
| Opnd* opnd1 = popOpnd(); |
| Opnd* opnd2 = popOpnd(); |
| pushOpnd(opnd1); |
| pushOpnd(opnd2); |
| } |
| //----------------------------------------------------------------------------- |
| // Arithmetic and logical operation byte codes |
| //----------------------------------------------------------------------------- |
| void JavaByteCodeTranslator::iadd() {genAdd(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::ladd() {genAdd(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::fadd() {genFPAdd(typeManager.getSingleType());} |
| void JavaByteCodeTranslator::dadd() {genFPAdd(typeManager.getDoubleType());} |
| void JavaByteCodeTranslator::isub() {genSub(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::lsub() {genSub(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::fsub() {genFPSub(typeManager.getSingleType());} |
| void JavaByteCodeTranslator::dsub() {genFPSub(typeManager.getDoubleType());} |
| void JavaByteCodeTranslator::imul() {genMul(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::lmul() {genMul(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::fmul() {genFPMul(typeManager.getSingleType());} |
| void JavaByteCodeTranslator::dmul() {genFPMul(typeManager.getDoubleType());} |
| void JavaByteCodeTranslator::idiv() {genDiv(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::ldiv() {genDiv(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::fdiv() {genFPDiv(typeManager.getSingleType());} |
| void JavaByteCodeTranslator::ddiv() {genFPDiv(typeManager.getDoubleType());} |
| void JavaByteCodeTranslator::irem() {genRem(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::lrem() {genRem(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::frem() {genFPRem(typeManager.getSingleType());} |
| void JavaByteCodeTranslator::drem() {genFPRem(typeManager.getDoubleType());} |
| void JavaByteCodeTranslator::ineg() {genNeg(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::lneg() {genNeg(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::fneg() {genNeg(typeManager.getSingleType());} |
| void JavaByteCodeTranslator::dneg() {genNeg(typeManager.getDoubleType());} |
| void JavaByteCodeTranslator::iand() {genAnd(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::land() {genAnd(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::ior() {genOr(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::lor() {genOr(typeManager.getInt64Type());} |
| void JavaByteCodeTranslator::ixor() {genXor(typeManager.getInt32Type());} |
| void JavaByteCodeTranslator::lxor() {genXor(typeManager.getInt64Type());} |
| void |
| JavaByteCodeTranslator::ishl() { |
| genShl(typeManager.getInt32Type(), ShiftMask_Masked); |
| } |
| void |
| JavaByteCodeTranslator::lshl() { |
| genShl(typeManager.getInt64Type(), ShiftMask_Masked); |
| } |
| void |
| JavaByteCodeTranslator::ishr() { |
| genShr(typeManager.getInt32Type(),SignedOp, ShiftMask_Masked); |
| } |
| void |
| JavaByteCodeTranslator::lshr() { |
| genShr(typeManager.getInt64Type(),SignedOp, ShiftMask_Masked); |
| } |
| void |
| JavaByteCodeTranslator::iushr(){ |
| genShr(typeManager.getInt32Type(),UnsignedOp, ShiftMask_Masked); |
| } |
| void |
| JavaByteCodeTranslator::lushr(){ |
| genShr(typeManager.getInt64Type(),UnsignedOp, ShiftMask_Masked); |
| } |
| void |
| JavaByteCodeTranslator::iinc(uint16 varIndex,I_32 amount) { |
| VarOpnd* varOpnd = (VarOpnd*)getVarOpndLdVar(JavaLabelPrepass::I,varIndex); |
| assert(varOpnd->isVarOpnd()); |
| Opnd* src1 = irBuilder.genLdVar(typeManager.getInt32Type(),varOpnd); |
| Opnd* src2 = irBuilder.genLdConstant((I_32)amount); |
| Opnd* result = irBuilder.genAdd(typeManager.getInt32Type(),Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| src1,src2); |
| irBuilder.genStVar(varOpnd,result); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // conversion byte codes |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::i2l() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt64Type(),Type::Int64,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::i2f() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getSingleType(),Type::Single,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::i2d() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getDoubleType(),Type::Double,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::l2i() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt32Type(),Type::Int32,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::l2f() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getSingleType(),Type::Single,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::l2d() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getDoubleType(),Type::Double,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::f2i() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt32Type(),Type::Int32,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::f2l() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt64Type(),Type::Int64,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::f2d() { |
| Opnd* src = popOpnd(); |
| Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never); |
| if (methodToCompile.isStrict()) |
| mod = mod | Modifier(Strict_Yes); |
| else |
| mod = mod | Modifier(Strict_No); |
| pushOpnd(irBuilder.genConv(typeManager.getDoubleType(),Type::Double,mod,src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::d2i() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt32Type(),Type::Int32,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::d2l() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt64Type(),Type::Int64,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::d2f() { |
| Opnd* src = popOpnd(); |
| Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never); |
| if (methodToCompile.isStrict()) |
| mod = mod | Modifier(Strict_Yes); |
| else |
| mod = mod | Modifier(Strict_No); |
| pushOpnd(irBuilder.genConv(typeManager.getSingleType(),Type::Single,mod,src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::i2b() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt32Type(),Type::Int8,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::i2c() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt32Type(),Type::UInt16,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::i2s() { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genConv(typeManager.getInt32Type(),Type::Int16,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src)); |
| } |
| //----------------------------------------------------------------------------- |
| // comparison byte codes |
| //----------------------------------------------------------------------------- |
| // |
| void JavaByteCodeTranslator::lcmp() {genThreeWayCmp(Type::Int64,Cmp_GT);} |
| void JavaByteCodeTranslator::fcmpl() {genThreeWayCmp(Type::Single,Cmp_GT);} |
| void JavaByteCodeTranslator::fcmpg() {genThreeWayCmp(Type::Single,Cmp_GT_Un);} |
| void JavaByteCodeTranslator::dcmpl() {genThreeWayCmp(Type::Double,Cmp_GT);} |
| void JavaByteCodeTranslator::dcmpg() {genThreeWayCmp(Type::Double,Cmp_GT_Un);} |
| |
| //----------------------------------------------------------------------------- |
| // control transfer byte codes |
| //----------------------------------------------------------------------------- |
| void JavaByteCodeTranslator::ifeq(U_32 targetOffset,U_32 nextOffset) { |
| genIf1(Cmp_EQ,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::ifne(U_32 targetOffset,U_32 nextOffset) { |
| genIf1(Cmp_NE_Un,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::iflt(U_32 targetOffset,U_32 nextOffset) { |
| genIf1Commute(Cmp_GT,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::ifge(U_32 targetOffset,U_32 nextOffset) { |
| genIf1(Cmp_GTE,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::ifgt(U_32 targetOffset,U_32 nextOffset) { |
| genIf1(Cmp_GT,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::ifle(U_32 targetOffset,U_32 nextOffset) { |
| genIf1Commute(Cmp_GTE,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::ifnull(U_32 targetOffset,U_32 nextOffset) { |
| genIfNull(Cmp_Zero,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::ifnonnull(U_32 targetOffset,U_32 nextOffset) { |
| genIfNull(Cmp_NonZero,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::if_icmpeq(U_32 targetOffset,U_32 nextOffset) { |
| genIf2(Cmp_EQ,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::if_icmpne(U_32 targetOffset,U_32 nextOffset) { |
| genIf2(Cmp_NE_Un,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::if_icmplt(U_32 targetOffset,U_32 nextOffset) { |
| genIf2Commute(Cmp_GT,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::if_icmpge(U_32 targetOffset,U_32 nextOffset) { |
| genIf2(Cmp_GTE,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::if_icmpgt(U_32 targetOffset,U_32 nextOffset) { |
| genIf2(Cmp_GT,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::if_icmple(U_32 targetOffset,U_32 nextOffset) { |
| genIf2Commute(Cmp_GTE,targetOffset,nextOffset); |
| } |
| void JavaByteCodeTranslator::if_acmpeq(U_32 targetOffset,U_32 nextOffset) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| LabelInst *target = getLabel(labelId(targetOffset)); |
| irBuilder.genBranch(Type::Object,Cmp_EQ,target,src1,src2); |
| } |
| |
| void |
| JavaByteCodeTranslator::if_acmpne(U_32 targetOffset,U_32 nextOffset) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| LabelInst *target = getLabel(labelId(targetOffset)); |
| irBuilder.genBranch(Type::Object,Cmp_NE_Un,target,src1,src2); |
| } |
| |
| void |
| JavaByteCodeTranslator::goto_(U_32 targetOffset,U_32 nextOffset) { |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| U_32 lid = labelId(targetOffset); |
| LabelInst *target = getLabel(lid); |
| irBuilder.genJump(target); |
| } |
| //----------------------------------------------------------------------------- |
| // jsr & ret byte codes for finally statements |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::jsr(U_32 targetOffset, U_32 nextOffset) { |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| irBuilder.genJSR(getLabel(labelId(targetOffset))); |
| } |
| |
| void |
| JavaByteCodeTranslator::ret(uint16 varIndex, const U_8* byteCodes) { |
| lastInstructionWasABranch = true; |
| checkStack(); |
| irBuilder.genRet(getVarOpndLdVar(JavaLabelPrepass::RET,varIndex)); |
| |
| retOffsets[currentOffset] = irBuilder.getLastGeneratedInst(); |
| } |
| //----------------------------------------------------------------------------- |
| // multy-way branch byte codes (switches) |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::tableswitch(JavaSwitchTargetsIter* iter) { |
| Opnd* opnd = popOpnd(); |
| lastInstructionWasABranch = true; |
| checkStack(); |
| // subtract the lower bound |
| Opnd* bias = irBuilder.genLdConstant((I_32)iter->getLowValue()); |
| Opnd* dst = irBuilder.genSub(bias->getType(),Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),opnd,bias); |
| LabelInst** labels = new (memManager) LabelInst*[iter->getNumTargets()]; |
| for (U_32 i=0; iter->hasNext(); i++) { |
| labels[i] = getLabel(labelId(iter->getNextTarget())); |
| } |
| LabelInst * defaultLabel = getLabel(labelId(iter->getDefaultTarget())); |
| irBuilder.genSwitch(iter->getNumTargets(),labels,defaultLabel,dst); |
| } |
| |
| void |
| JavaByteCodeTranslator::lookupswitch(JavaLookupSwitchTargetsIter* iter) { |
| Opnd* opnd = popOpnd(); |
| lastInstructionWasABranch = true; |
| checkStack(); |
| // generate a sequence of branches |
| while (iter->hasNext()) { |
| U_32 key; |
| U_32 offset = iter->getNextTarget(&key); |
| // load the key |
| Opnd* value = irBuilder.genLdConstant((I_32)key); |
| LabelInst *target = getLabel(labelId(offset)); |
| irBuilder.genBranch(Type::Int32,Cmp_EQ,target,opnd,value); |
| // break the basic block |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| // generate a jump to the default label |
| LabelInst *defaultLabel = getLabel(labelId(iter->getDefaultTarget())); |
| irBuilder.genJump(defaultLabel); |
| } |
| //----------------------------------------------------------------------------- |
| // method return byte codes |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::ireturn(U_32 off) { |
| genReturn(JavaLabelPrepass::I,off); |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| void |
| JavaByteCodeTranslator::lreturn(U_32 off) { |
| genReturn(JavaLabelPrepass::L,off); |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| void |
| JavaByteCodeTranslator::freturn(U_32 off) { |
| genReturn(JavaLabelPrepass::F,off); |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| void |
| JavaByteCodeTranslator::dreturn(U_32 off) { |
| genReturn(JavaLabelPrepass::D,off); |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| void |
| JavaByteCodeTranslator::areturn(U_32 off) { |
| genReturn(JavaLabelPrepass::A,off); |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| void |
| JavaByteCodeTranslator::return_(U_32 off) { |
| genReturn(off); |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| //----------------------------------------------------------------------------- |
| // LinkingException throw |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::linkingException(U_32 constPoolIndex, U_32 operation) { |
| Class_Handle enclosingDrlVMClass = methodToCompile.getParentHandle(); |
| irBuilder.genThrowLinkingException(enclosingDrlVMClass, constPoolIndex, operation); |
| } |
| //----------------------------------------------------------------------------- |
| // for invoke emulation if resolution fails |
| //----------------------------------------------------------------------------- |
| void JavaByteCodeTranslator::pseudoInvoke(const char* methodSig) |
| { |
| U_32 numArgs = JavaLabelPrepass::getNumArgsBySignature(methodSig); |
| |
| // pop numArgs items |
| while (numArgs--) { |
| popOpnd(); |
| } |
| // recognize and push respective returnType |
| Type* retType = JavaLabelPrepass::getRetTypeBySignature(compilationInterface, methodToCompile.getParentHandle(), methodSig); |
| assert(retType); |
| |
| // push NULL as a returned object |
| if (retType->tag != Type::Void) { |
| pushOpnd(irBuilder.genLdNull()); |
| } |
| } |
| |
| //----------------------------------------------------------------------------- |
| // method invocation byte codes |
| //----------------------------------------------------------------------------- |
| Opnd** |
| JavaByteCodeTranslator::popArgs(U_32 numArgs) { |
| // pop source operands |
| Opnd** srcOpnds = new (memManager) Opnd*[numArgs]; |
| for (int i=numArgs-1; i>=0; i--) |
| srcOpnds[i] = popOpnd(); |
| return srcOpnds; |
| } |
| |
| //Helper class used to initialize unresolved method ptrs |
| class JavaMethodSignature : public MethodSignature { |
| public: |
| JavaMethodSignature(MemoryManager& mm, CompilationInterface ci, bool instanceMethod, Class_Handle cl, const char* sigStr){ |
| signatureStr = sigStr; |
| nParams = JavaLabelPrepass::getNumArgsBySignature(sigStr) + (instanceMethod ? 1 : 0); |
| const char* sigSuffix = sigStr; |
| if (nParams > 0) { |
| paramTypes = new (mm) Type*[nParams]; |
| U_32 i = 0; |
| if (instanceMethod) { |
| paramTypes[0] = ci.getTypeManager().getUnresolvedObjectType(); |
| i++; |
| } |
| sigSuffix++; |
| for (; i < nParams; i++) { |
| U_32 len = 0; |
| Type* type = JavaLabelPrepass::getTypeByDescriptorString(ci, cl, sigSuffix, len); |
| assert(type!=NULL); |
| paramTypes[i] = type; |
| sigSuffix+=len; |
| } |
| } else { |
| paramTypes = NULL; |
| } |
| retType = JavaLabelPrepass::getRetTypeBySignature(ci, cl, sigSuffix); |
| } |
| |
| virtual ~JavaMethodSignature(){}; |
| virtual U_32 getNumParams() const { return nParams;} |
| virtual Type** getParamTypes() const { return paramTypes;} |
| virtual Type* getRetType() const {return retType;} |
| virtual const char* getSignatureString() const {return signatureStr;} |
| private: |
| U_32 nParams; |
| Type** paramTypes; |
| Type* retType; |
| const char* signatureStr; |
| |
| }; |
| |
| void JavaByteCodeTranslator::genCallWithResolve(JavaByteCodes bc, unsigned cpIndex) { |
| assert(bc == OPCODE_INVOKESPECIAL || bc == OPCODE_INVOKESTATIC || bc == OPCODE_INVOKEVIRTUAL || bc == OPCODE_INVOKEINTERFACE); |
| bool isStatic = bc == OPCODE_INVOKESTATIC; |
| |
| |
| ObjectType* enclosingClass = methodToCompile.getParentType()->asObjectType(); |
| assert(enclosingClass!=NULL); |
| const char* methodSig = methodSignatureString(cpIndex); |
| assert(methodSig); |
| JavaMethodSignature* sig = new (memManager) JavaMethodSignature(irBuilder.getIRManager()->getMemoryManager(), |
| compilationInterface, !isStatic, (Class_Handle)enclosingClass->getVMTypeHandle(), methodSig); |
| U_32 numArgs = sig->getNumParams(); |
| assert(numArgs > 0 || isStatic); |
| |
| Opnd** args = popArgs(numArgs); |
| Type* returnType = sig->getRetType(); |
| |
| |
| if (bc != OPCODE_INVOKEINTERFACE) { |
| const char* kname = CompilationInterface::getMethodClassName(methodToCompile.getParentHandle(), cpIndex); |
| const char* mname = CompilationInterface::getMethodName(methodToCompile.getParentHandle(), cpIndex); |
| if (VMMagicUtils::isVMMagicClass(kname)) { |
| assert(bc == OPCODE_INVOKESTATIC || bc == OPCODE_INVOKEVIRTUAL); |
| UNUSED bool res = genVMMagic(mname, numArgs, args, returnType); |
| assert(res); |
| return; |
| } else if (isVMHelperClass(kname)) { |
| assert(bc == OPCODE_INVOKESTATIC); |
| bool res = genVMHelper(mname, numArgs, args, returnType); |
| if (res) { //method is not a registered vmhelper name |
| return; |
| } |
| } |
| } |
| |
| Opnd* tauNullCheckedFirstArg = bc == OPCODE_INVOKESTATIC ? irBuilder.genTauSafe() :irBuilder.genTauCheckNull(args[0]); |
| Opnd* tauTypesChecked = NULL;// let IRBuilder handle types |
| |
| Opnd* dst = irBuilder.genIndirectCallWithResolve(returnType, tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args, enclosingClass, bc, cpIndex, sig); |
| if (returnType->tag != Type::Void) { |
| pushOpnd(dst); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::invokevirtual(U_32 constPoolIndex) { |
| MethodDesc* methodDesc = compilationInterface.getVirtualMethod(methodToCompile.getParentHandle(), constPoolIndex); |
| if (!methodDesc) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_INVOKEVIRTUAL); |
| } |
| genCallWithResolve(OPCODE_INVOKEVIRTUAL, constPoolIndex); |
| return; |
| } |
| jitrino_assert(methodDesc); |
| U_32 numArgs = methodDesc->getNumParams(); |
| Opnd** srcOpnds = popArgs(numArgs); |
| Type* returnType = methodDesc->getReturnType(); |
| |
| const char* className = methodDesc->getParentType()->getName(); |
| if (VMMagicUtils::isVMMagicClass(className)) { |
| UNUSED bool res = genVMMagic(methodDesc->getName(), numArgs, srcOpnds, returnType); |
| assert(res); |
| return; |
| } |
| |
| // callvirt can throw a null pointer exception |
| Opnd *tauNullChecked = irBuilder.genTauCheckNull(srcOpnds[0]); |
| Opnd* thisOpnd = srcOpnds[0]; |
| if (methodDesc->getParentType() != thisOpnd->getType()) { |
| if(Log::isEnabled()) { |
| Log::out()<<"CHECKVIRTUAL "; thisOpnd->printWithType(Log::out()); Log::out() << " : "; |
| methodDesc->getParentType()->print(Log::out()); |
| Log::out() <<"."<<methodDesc->getName()<<" "<< (int)methodDesc->getByteCodeSize()<< ::std::endl; |
| } |
| |
| Type* type = thisOpnd->getType(); |
| if (!type->isNullObject() && !type->isUnresolvedType() && !type->isInterface()) { |
| // needs to refine the method descriptor before doing any optimization |
| MethodDesc *overriding = compilationInterface.getOverridingMethod( |
| (NamedType*)type,methodDesc); |
| if (overriding && overriding != methodDesc) { |
| methodDesc = overriding; |
| } |
| } |
| } |
| |
| if (returnType==NULL) { |
| // This means that it was not resolved successfully but it can be resolved later |
| // inside the callee (with some "magic" custom class loader for example) |
| // Or respective exception will be thrown there (in the callee) at the attempt to create (new) |
| // an object of unresolved type |
| const char* methodSig_string = methodSignatureString(constPoolIndex); |
| returnType = JavaLabelPrepass::getRetTypeBySignature(compilationInterface, methodToCompile.getParentHandle(), methodSig_string); |
| } |
| |
| Opnd* dst = irBuilder.genTauVirtualCall(methodDesc,returnType, |
| tauNullChecked, |
| 0, // let IRBuilder handle types |
| numArgs, |
| srcOpnds); |
| // push the return type |
| if (returnType->tag != Type::Void) |
| pushOpnd(dst); |
| } |
| |
| void |
| JavaByteCodeTranslator::invokespecial(U_32 constPoolIndex) { |
| MethodDesc* methodDesc = compilationInterface.getSpecialMethod(methodToCompile.getParentHandle(), constPoolIndex); |
| if (!methodDesc) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_INVOKESPECIAL); |
| } |
| genCallWithResolve(OPCODE_INVOKESPECIAL, constPoolIndex); |
| return; |
| } |
| jitrino_assert(methodDesc); |
| U_32 numArgs = methodDesc->getNumParams(); |
| Opnd** srcOpnds = popArgs(numArgs); |
| Type* returnType = methodDesc->getReturnType(); |
| // invokespecial can throw a null pointer exception |
| Opnd *tauNullChecked = irBuilder.genTauCheckNull(srcOpnds[0]); |
| Opnd* dst; |
| |
| if (returnType == NULL) { |
| // This means that it was not resolved successfully but it can be resolved later |
| // inside the callee (with some "magic" custom class loader for example) |
| // Or respective exception will be thrown there (in the callee) at the attempt to create (new) |
| // an object of unresolved type |
| returnType = typeManager.getNullObjectType(); |
| } |
| dst = irBuilder.genDirectCall(methodDesc, |
| returnType, |
| tauNullChecked, |
| 0, // let IRBuilder check types |
| numArgs, |
| srcOpnds); |
| |
| // push the return type |
| if (returnType->tag != Type::Void) { |
| pushOpnd(dst); |
| } |
| |
| } |
| |
| void |
| JavaByteCodeTranslator::invokestatic(U_32 constPoolIndex) { |
| MethodDesc* methodDesc = compilationInterface.getStaticMethod(methodToCompile.getParentHandle(), constPoolIndex); |
| if (!methodDesc) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_INVOKESTATIC); |
| } |
| genCallWithResolve(OPCODE_INVOKESTATIC, constPoolIndex); |
| return; |
| } |
| |
| jitrino_assert(methodDesc); |
| U_32 numArgs = methodDesc->getNumParams(); |
| Opnd** srcOpnds = popArgs(numArgs); |
| Type *returnType = methodDesc->getReturnType(); |
| if (returnType == NULL) { |
| // This means that it was not resolved successfully but it can be resolved later |
| // inside the callee (with some "magic" custom class loader for example) |
| // Or respective exception will be thrown there (in the callee) at the attempt to create (new) |
| // an object of unresolved type |
| returnType = typeManager.getNullObjectType(); |
| } |
| // |
| // Try some optimizations for Min, Max, Abs... |
| // |
| if (translationFlags.genMinMaxAbs == true && |
| genMinMax(methodDesc,numArgs,srcOpnds,returnType)) { |
| return; |
| } else |
| genInvokeStatic(methodDesc,numArgs,srcOpnds,returnType); |
| } |
| |
| void |
| JavaByteCodeTranslator::invokeinterface(U_32 constPoolIndex,U_32 count) { |
| MethodDesc* methodDesc = compilationInterface.getInterfaceMethod(methodToCompile.getParentHandle(), constPoolIndex); |
| if (!methodDesc) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_INVOKEINTERFACE); |
| } |
| genCallWithResolve(OPCODE_INVOKEINTERFACE, constPoolIndex); |
| return; |
| } |
| jitrino_assert(methodDesc); |
| U_32 numArgs = methodDesc->getNumParams(); |
| Opnd** srcOpnds = popArgs(numArgs); |
| Type* returnType = methodDesc->getReturnType(); |
| // callintf can throw a null pointer exception |
| Opnd *tauNullChecked = irBuilder.genTauCheckNull(srcOpnds[0]); |
| Opnd* thisOpnd = srcOpnds[0]; |
| Opnd* dst; |
| if (methodDesc->getParentType() != thisOpnd->getType()) { |
| Type * type = thisOpnd->getType(); |
| if (!type->isNullObject() && !type->isUnresolvedObject() && !type->isInterface()) { |
| // need to refine the method descriptor before doing any optimization |
| MethodDesc *overriding = compilationInterface.getOverridingMethod( |
| (NamedType*)type,methodDesc); |
| if (overriding && overriding != methodDesc && !overriding->getParentType()->isInterface()) { |
| methodDesc = overriding; |
| } |
| } |
| } |
| |
| if (returnType == NULL) { |
| // This means that it was not resolved successfully but it can be resolved later |
| // inside the callee (with some "magic" custom class loader for example) |
| // Or respective exception will be thrown there (in the callee) at the attempt to create (new) |
| // an object of unresolved type |
| const char* methodSig_string = methodSignatureString(constPoolIndex); |
| returnType = JavaLabelPrepass::getRetTypeBySignature(compilationInterface, methodToCompile.getParentHandle(), methodSig_string); |
| } |
| dst = irBuilder.genTauVirtualCall(methodDesc, |
| returnType, |
| tauNullChecked, |
| 0, // let IRBuilder handle types |
| numArgs, |
| srcOpnds); |
| // push the return type |
| if (returnType->tag != Type::Void) |
| pushOpnd(dst); |
| } |
| //----------------------------------------------------------------------------- |
| // object allocation byte codes |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::new_(U_32 constPoolIndex) { |
| NamedType* type = compilationInterface.getNamedType(methodToCompile.getParentHandle(), constPoolIndex, ResolveNewCheck_DoCheck); |
| jitrino_assert(type); |
| if (type->isUnresolvedObject()) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_NEW); |
| } |
| pushOpnd(irBuilder.genNewObjWithResolve(methodToCompile.getParentType()->asObjectType(), constPoolIndex)); |
| } else { |
| #ifdef _DEBUG |
| const char* typeName = type->getName(); |
| assert(!VMMagicUtils::isVMMagicClass(typeName)); |
| #endif |
| pushOpnd(irBuilder.genNewObj(type)); |
| } |
| } |
| void |
| JavaByteCodeTranslator::newarray(U_8 atype) { |
| NamedType* type = NULL; |
| switch (atype) { |
| case 4: // boolean |
| type = typeManager.getBooleanType(); break; |
| case 5: // char |
| type = typeManager.getCharType(); break; |
| case 6: // float |
| type = typeManager.getSingleType(); break; |
| case 7: // double |
| type = typeManager.getDoubleType(); break; |
| case 8: // byte |
| type = typeManager.getInt8Type(); break; |
| case 9: // short |
| type = typeManager.getInt16Type(); break; |
| case 10: // int |
| type = typeManager.getInt32Type(); break; |
| case 11: // long |
| type = typeManager.getInt64Type(); break; |
| default: jitrino_assert(0); |
| } |
| Opnd* arrayOpnd = irBuilder.genNewArray(type,popOpnd()); |
| pushOpnd(arrayOpnd); |
| if (translationFlags.optArrayInit) { |
| const U_8* byteCodes = parser.getByteCodes(); |
| const U_32 byteCodeLength = parser.getByteCodeLength(); |
| U_32 offset = currentOffset + 2/*newarray length*/; |
| U_32 length = checkForArrayInitializer(arrayOpnd, byteCodes, offset, byteCodeLength); |
| currentOffset += length; |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::anewarray(U_32 constPoolIndex) { |
| NamedType* type = compilationInterface.getNamedType(methodToCompile.getParentHandle(), constPoolIndex); |
| Opnd* sizeOpnd = popOpnd(); |
| if (type->isUnresolvedType()) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_ANEWARRAY); |
| } |
| //res type can be an array of multi array with uninitialized dimensions. |
| pushOpnd(irBuilder.genNewArrayWithResolve(type, sizeOpnd, methodToCompile.getParentType()->asObjectType(), constPoolIndex)); |
| } else { |
| pushOpnd(irBuilder.genNewArray(type,sizeOpnd)); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::multianewarray(U_32 constPoolIndex,U_8 dimensions) { |
| NamedType* arraytype = compilationInterface.getNamedType(methodToCompile.getParentHandle(), constPoolIndex); |
| assert(arraytype->isArray()); |
| jitrino_assert(dimensions > 0); |
| Opnd** countOpnds = new (memManager) Opnd*[dimensions]; |
| // pop the sizes |
| for (int i = dimensions - 1; i >= 0; i--) { |
| countOpnds[i] = popOpnd(); |
| } |
| if (arraytype->isUnresolvedType()) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_MULTIANEWARRAY); |
| } |
| pushOpnd(irBuilder.genMultianewarrayWithResolve( |
| arraytype, methodToCompile.getParentType()->asObjectType(),constPoolIndex, dimensions,countOpnds |
| )); |
| } else { |
| pushOpnd(irBuilder.genMultianewarray(arraytype,dimensions,countOpnds)); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::arraylength() { |
| Type::Tag arrayLenType = Type::Int32; |
| pushOpnd(irBuilder.genArrayLen(typeManager.getInt32Type(),arrayLenType,popOpnd())); |
| } |
| |
| void |
| JavaByteCodeTranslator::athrow() { |
| lastInstructionWasABranch = true; |
| irBuilder.genThrow(Throw_NoModifier, popOpnd()); |
| LabelInst *label = irBuilder.createLabel(); |
| cfgBuilder.genBlockAfterCurrent(label); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // type checking byte codes |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::checkcast(U_32 constPoolIndex) { |
| NamedType *type = compilationInterface.getNamedType(methodToCompile.getParentHandle(), constPoolIndex); |
| Opnd* objOpnd = popOpnd(); |
| if (type->isUnresolvedType()) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_CHECKCAST); |
| } |
| pushOpnd(irBuilder.genCastWithResolve(objOpnd, type, methodToCompile.getParentType()->asObjectType(), constPoolIndex)); |
| } else { |
| pushOpnd(irBuilder.genCast(objOpnd, type)); |
| } |
| } |
| |
| int |
| JavaByteCodeTranslator::instanceof(const U_8* bcp, U_32 constPoolIndex, U_32 off) { |
| NamedType *type = compilationInterface.getNamedType(methodToCompile.getParentHandle(), constPoolIndex); |
| Opnd* src = popOpnd(); |
| Type* srcType = src->getType(); |
| Opnd* res = NULL; |
| |
| if (type->isUnresolvedType()) { |
| if (!typeManager.isLazyResolutionMode()) { |
| linkingException(constPoolIndex, OPCODE_INSTANCEOF); |
| } |
| res = irBuilder.genInstanceOfWithResolve(src, methodToCompile.getParentType()->asObjectType(), constPoolIndex); |
| } else if( !srcType->isUnresolvedType() |
| && !srcType->isInterface() |
| && !Simplifier::isExactType(src) |
| && ((ObjectType*)type)->isFinalClass() ) |
| { |
| // if target type is final just compare VTables |
| // This can not be done by Simplifier as it can not generate branches |
| // (srcType->isExactType() case will be simplified by Simplifier) |
| |
| Type* intPtrType = typeManager.getIntPtrType(); |
| |
| LabelInst* ObjIsNullLabel = irBuilder.createLabel(); |
| LabelInst* Exit = irBuilder.createLabel(); |
| VarOpnd* resVar = irBuilder.genVarDef(intPtrType, false); |
| |
| newFallthroughBlock(); |
| |
| Opnd * nullObj = irBuilder.genLdNull(); |
| irBuilder.genBranch(Type::IntPtr, Cmp_EQ, ObjIsNullLabel, nullObj, src); |
| |
| // src is not null here |
| newFallthroughBlock(); |
| Opnd* srcIsSafe = irBuilder.genTauSafe(); |
| Opnd* dynamicVTable = irBuilder.genTauLdVTable(src, srcIsSafe, srcType); |
| Opnd* staticVTable = irBuilder.genGetVTable((ObjectType*) type); |
| irBuilder.genStVar(resVar, irBuilder.genCmp(intPtrType,Type::IntPtr,Cmp_EQ,staticVTable,dynamicVTable)); |
| irBuilder.genJump(Exit); |
| |
| // src is null, instanceOf returns 0 |
| irBuilder.genLabel(ObjIsNullLabel); |
| cfgBuilder.genBlockAfterCurrent(ObjIsNullLabel); |
| Opnd * zero = irBuilder.genLdConstant((I_32)0); |
| irBuilder.genStVar(resVar, zero); |
| irBuilder.genJump(Exit); |
| |
| irBuilder.genLabel(Exit); |
| cfgBuilder.genBlockAfterCurrent(Exit); |
| res = irBuilder.genLdVar(intPtrType,resVar); |
| } else { |
| res = irBuilder.genInstanceOf(src,type); |
| } |
| |
| assert(res); |
| pushOpnd(res); |
| return 3; |
| } |
| |
| // |
| // synchronization |
| // |
| void |
| JavaByteCodeTranslator::monitorenter() { |
| if (translationFlags.ignoreSync) |
| popOpnd(); |
| else if (translationFlags.syncAsEnterFence) |
| irBuilder.genMonitorEnterFence(popOpnd()); |
| else |
| irBuilder.genMonitorEnter(popOpnd()); |
| } |
| |
| void |
| JavaByteCodeTranslator::monitorexit() { |
| if (translationFlags.ignoreSync || translationFlags.syncAsEnterFence) |
| popOpnd(); |
| else |
| irBuilder.genMonitorExit(popOpnd()); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // variable access helpers |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::genLdVar(U_32 varIndex,JavaLabelPrepass::JavaVarType javaType) { |
| Opnd *var = getVarOpndLdVar(javaType,varIndex); |
| if (VMMagicUtils::isVMMagicClass(var->getType()->getName())) { |
| var->setType(convertVMMagicType2HIR(typeManager, var->getType())); |
| } |
| Opnd *opnd; |
| if (var->isVarOpnd()) { |
| opnd = irBuilder.genLdVar(var->getType(),(VarOpnd*)var); |
| } else { |
| opnd = var; |
| } |
| pushOpnd(opnd); |
| } |
| |
| void |
| JavaByteCodeTranslator::genTypeStVar(uint16 varIndex) { |
| Opnd *src = popOpnd(); |
| JavaLabelPrepass::JavaVarType javaType; |
| if (src->getType() == typeManager.getIntPtrType()) |
| javaType = JavaLabelPrepass::RET; |
| else |
| javaType = JavaLabelPrepass::A; |
| VarOpnd *var = getVarOpndStVar(javaType,varIndex,src); |
| if (var != NULL) { |
| irBuilder.genStVar(var,src); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::genStVar(U_32 varIndex,JavaLabelPrepass::JavaVarType javaType) { |
| Opnd *src = popOpnd(); |
| VarOpnd *var = getVarOpndStVar(javaType,varIndex,src); |
| if (var != NULL) |
| irBuilder.genStVar(var,src); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // method return helpers |
| //----------------------------------------------------------------------------- |
| bool |
| JavaByteCodeTranslator::needsReturnLabel(U_32 off) { |
| if (!moreThanOneReturn && methodToCompile.getByteCodeSize()-1 != off) { |
| if (!jumpToTheEnd) { |
| // allocate one more label |
| labels[numLabels++] = (LabelInst*)irBuilder.getInstFactory()->makeLabel(); |
| } |
| jumpToTheEnd = true; |
| moreThanOneReturn = true; |
| } |
| return moreThanOneReturn; |
| } |
| |
| // for non-void returns |
| void |
| JavaByteCodeTranslator::genReturn(JavaLabelPrepass::JavaVarType javaType, U_32 off) { |
| Opnd *ret = popOpndStVar(); |
| if (methodToCompile.isSynchronized()) { |
| // Create a new block to break exception region. The monexit exception should |
| // go to unwind. |
| cfgBuilder.genBlock(irBuilder.createLabel()); |
| if (methodToCompile.isStatic()) { |
| //irBuilder.genTypeMonitorExit(methodToCompile.getParentType()); |
| Opnd* classObjectOpnd = irBuilder.genGetClassObj((ObjectType*) methodToCompile.getParentType()); |
| pushOpnd(classObjectOpnd); |
| genMethodMonitorExit(); |
| } else { |
| genLdVar(0,JavaLabelPrepass::A); |
| genMethodMonitorExit(); |
| } |
| } |
| irBuilder.genReturn(ret,javaTypeMap[javaType]); |
| opndStack.makeEmpty(); |
| } |
| |
| // for void returns |
| void |
| JavaByteCodeTranslator::genReturn(U_32 off) { |
| if (methodToCompile.isSynchronized()) { |
| // Create a new block to break exception region. The monexit exception should |
| // go to unwind. |
| cfgBuilder.genBlock(irBuilder.createLabel()); |
| if (methodToCompile.isStatic()) { |
| // irBuilder.genTypeMonitorExit(methodToCompile.getParentType()); |
| Opnd* classObjectOpnd = irBuilder.genGetClassObj((ObjectType*) methodToCompile.getParentType()); |
| pushOpnd(classObjectOpnd); |
| genMethodMonitorExit(); |
| } else { |
| genLdVar(0,JavaLabelPrepass::A); |
| genMethodMonitorExit(); |
| } |
| } |
| irBuilder.genReturn(); |
| // some manually written test case can leave non empty opnd stack after return |
| opndStack.makeEmpty(); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // arithmetic & logical helpers |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::genAdd(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genAdd(dstType,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genSub(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genSub(dstType,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genMul(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genMul(dstType,Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No),src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genDiv(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genDiv(dstType,Modifier(SignedOp)|Modifier(Strict_No),src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genRem(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genRem(dstType,Modifier(SignedOp)|Modifier(Strict_No),src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genNeg(Type* dstType) { |
| Opnd* src = popOpnd(); |
| pushOpnd(irBuilder.genNeg(dstType,src)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genFPAdd(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never); |
| if (methodToCompile.isStrict()) |
| mod = mod | Modifier(Strict_Yes); |
| else |
| mod = mod | Modifier(Strict_No); |
| pushOpnd(irBuilder.genAdd(dstType,mod,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genFPSub(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never); |
| if (methodToCompile.isStrict()) |
| mod = mod | Modifier(Strict_Yes); |
| else |
| mod = mod | Modifier(Strict_No); |
| pushOpnd(irBuilder.genSub(dstType,mod,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genFPMul(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never); |
| if (methodToCompile.isStrict()) |
| mod = mod | Modifier(Strict_Yes); |
| else |
| mod = mod | Modifier(Strict_No); |
| pushOpnd(irBuilder.genMul(dstType,mod,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genFPDiv(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| Modifier mod = SignedOp; |
| if (methodToCompile.isStrict()) |
| mod = mod | Modifier(Strict_Yes); |
| else |
| mod = mod | Modifier(Strict_No); |
| pushOpnd(irBuilder.genDiv(dstType,mod,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genFPRem(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| Modifier mod = SignedOp; |
| if (methodToCompile.isStrict()) |
| mod = mod | Modifier(Strict_Yes); |
| else |
| mod = mod | Modifier(Strict_No); |
| pushOpnd(irBuilder.genRem(dstType,mod,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genAnd(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genAnd(dstType,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genOr(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genOr(dstType,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genXor(Type* dstType) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| pushOpnd(irBuilder.genXor(dstType,src1,src2)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genShl(Type* type, ShiftMaskModifier mod) { |
| Opnd* shiftAmount = popOpnd(); |
| Opnd* value = popOpnd(); |
| pushOpnd(irBuilder.genShl(type,mod,value,shiftAmount)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genShr(Type* type, SignedModifier mod1, |
| ShiftMaskModifier mod2) { |
| Opnd* shiftAmount = popOpnd(); |
| Opnd* value = popOpnd(); |
| pushOpnd(irBuilder.genShr(type,Modifier(mod1)|Modifier(mod2), value, shiftAmount)); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // array access helpers |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::genArrayLoad(Type* type) { |
| Opnd* index = popOpnd(); |
| Opnd* base = popOpnd(); |
| pushOpnd(irBuilder.genLdElem(type,base,index)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genTypeArrayLoad() { |
| Opnd* index = popOpnd(); |
| Opnd* base = popOpnd(); |
| Type *type = base->getType(); |
| if (!type->isArrayType()) { |
| if (type->isNullObject()) { |
| irBuilder.genThrowSystemException(CompilationInterface::Exception_NullPointer); |
| pushOpnd(irBuilder.genLdNull()); |
| return; |
| } |
| if (Log::isEnabled()) { |
| Log::out() << "Array type is "; |
| type->print(Log::out()); Log::out() << ::std::endl; |
| stateInfo->stack[5].type->print(Log::out()); Log::out() << ::std::endl; |
| Log::out() << "CONFLICT IN ARRAY ACCESS\n"; |
| } |
| type = typeManager.getSystemObjectType(); |
| } else |
| type = ((ArrayType*)type)->getElementType(); |
| pushOpnd(irBuilder.genLdElem(type,base,index)); |
| } |
| |
| void |
| JavaByteCodeTranslator::genArrayStore(Type* type) { |
| Opnd* value = popOpnd(); |
| Opnd* index = popOpnd(); |
| Opnd* base = popOpnd(); |
| irBuilder.genStElem(type,base,index,value); |
| } |
| |
| void |
| JavaByteCodeTranslator::genTypeArrayStore() { |
| Opnd* value = popOpnd(); |
| Opnd* index = popOpnd(); |
| Opnd* base = popOpnd(); |
| Type *type = base->getType(); |
| if (!type->isArrayType()) { |
| if (type->isNullObject()) { |
| irBuilder.genThrowSystemException(CompilationInterface::Exception_NullPointer); |
| return; |
| } |
| type = typeManager.getSystemObjectType(); |
| Log::out() << "CONFLICT IN ARRAY ACCESS\n"; |
| } else |
| type = ((ArrayType*)type)->getElementType(); |
| irBuilder.genStElem(type,base,index,value); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // control transfer helpers |
| //----------------------------------------------------------------------------- |
| void |
| JavaByteCodeTranslator::genIf1(ComparisonModifier mod, |
| I_32 targetOffset, |
| I_32 nextOffset) { |
| Opnd* src1 = popOpnd(); |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| LabelInst *target = getLabel(labelId(targetOffset)); |
| Opnd* src2 = irBuilder.genLdConstant((I_32)0); |
| irBuilder.genBranch(Type::Int32,mod,target,src1,src2); |
| } |
| |
| void |
| JavaByteCodeTranslator::genIf1Commute(ComparisonModifier mod, |
| I_32 targetOffset, |
| I_32 nextOffset) { |
| Opnd* src1 = popOpnd(); |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| LabelInst *target = getLabel(labelId(targetOffset)); |
| Opnd* src2 = irBuilder.genLdConstant((I_32)0); |
| irBuilder.genBranch(Type::Int32,mod,target,src2,src1); |
| } |
| |
| void |
| JavaByteCodeTranslator::genIf2(ComparisonModifier mod, |
| I_32 targetOffset, |
| I_32 nextOffset) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| LabelInst *target = getLabel(labelId(targetOffset)); |
| irBuilder.genBranch(Type::Int32,mod,target,src1,src2); |
| } |
| |
| void |
| JavaByteCodeTranslator::genIf2Commute(ComparisonModifier mod, |
| I_32 targetOffset, |
| I_32 nextOffset) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| LabelInst *target = getLabel(labelId(targetOffset)); |
| irBuilder.genBranch(Type::Int32,mod,target,src2,src1); |
| } |
| |
| void |
| JavaByteCodeTranslator::genIfNull(ComparisonModifier mod, |
| I_32 targetOffset, |
| I_32 nextOffset) { |
| Opnd* src1 = popOpnd(); |
| if (targetOffset == nextOffset) |
| return; |
| if (targetOffset < nextOffset) { |
| irBuilder.genPseudoThrow(); |
| } |
| lastInstructionWasABranch = true; |
| checkStack(); |
| LabelInst *target = getLabel(labelId(targetOffset)); |
| |
| if (src1->getType() == typeManager.getNullObjectType()) { |
| if (mod == Cmp_Zero) |
| irBuilder.genJump(target); |
| return; |
| } |
| irBuilder.genBranch(Type::SystemObject,mod,target,src1); |
| } |
| |
| void |
| JavaByteCodeTranslator::genThreeWayCmp(Type::Tag cmpType, |
| ComparisonModifier src1ToSrc2) { |
| Opnd* src2 = popOpnd(); |
| Opnd* src1 = popOpnd(); |
| Type* dstType = typeManager.getInt32Type(); |
| pushOpnd(irBuilder.genCmp3(dstType,cmpType,src1ToSrc2,src1,src2)); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // method calls helpers |
| //----------------------------------------------------------------------------- |
| |
| void |
| JavaByteCodeTranslator::genInvokeStatic(MethodDesc * methodDesc, |
| U_32 numArgs, |
| Opnd ** srcOpnds, |
| Type * returnType) { |
| Opnd *dst; |
| |
| const char* kname = methodDesc->getParentType()->getName(); |
| const char* mname = methodDesc->getName(); |
| if (VMMagicUtils::isVMMagicClass(kname)) { |
| UNUSED bool res = genVMMagic(mname, numArgs, srcOpnds, returnType); |
| assert(res); |
| return; |
| } else if (isVMHelperClass(kname) && !methodDesc->isNative()) { |
| bool res = genVMHelper(mname, numArgs, srcOpnds, returnType); |
| if (res) { |
| return; |
| } |
| } |
| Opnd *tauNullChecked = irBuilder.genTauSafe(); // always safe, is a static method call |
| Type* resType = returnType; |
| if (VMMagicUtils::isVMMagicClass(resType->getName())) { |
| resType = convertVMMagicType2HIR(typeManager, resType); |
| } |
| dst = irBuilder.genDirectCall(methodDesc, |
| resType, |
| tauNullChecked, |
| 0, // let IRBuilder check types |
| numArgs, |
| srcOpnds); |
| if (returnType->tag != Type::Void) |
| pushOpnd(dst); |
| } |
| |
| void |
| JavaByteCodeTranslator::newFallthroughBlock() { |
| LabelInst * labelInst = irBuilder.createLabel(); |
| irBuilder.genFallThroughLabel(labelInst); |
| cfgBuilder.genBlockAfterCurrent(labelInst); |
| } |
| |
| bool |
| JavaByteCodeTranslator::genMinMax(MethodDesc * methodDesc, |
| U_32 numArgs, |
| Opnd ** srcOpnds, |
| Type * returnType) { |
| |
| const char *className = methodDesc->getParentType()->getName(); |
| if (strcmp(className, "java/lang/Math") == 0) { |
| const char *methodName = methodDesc->getName(); |
| // |
| // Check for certain math methods and inline them |
| // |
| if (strcmp(methodName, "min") == 0) { |
| assert(numArgs == 2); |
| Opnd *src0 = srcOpnds[0]; |
| Opnd *src1 = srcOpnds[1]; |
| Type *type = src0->getType(); |
| assert(type == src1->getType()); |
| |
| IRManager& irm = *irBuilder.getIRManager(); |
| MethodDesc& md = irm.getMethodDesc(); |
| if (Log::isEnabled()) { |
| Log::out() << "Saw call to java/lang/Math::min from " |
| << md.getParentType()->getName() |
| << "::" |
| << md.getName() |
| << ::std::endl; |
| } |
| Opnd *res = irBuilder.genMin(type, src0, src1); |
| if (res) { |
| pushOpnd(res); |
| return true; |
| } |
| } else if (strcmp(methodName, "max") == 0) { |
| assert(numArgs == 2); |
| Opnd *src0 = srcOpnds[0]; |
| Opnd *src1 = srcOpnds[1]; |
| Type *type = src0->getType(); |
| assert(type == src1->getType()); |
| |
| IRManager& irm = *irBuilder.getIRManager(); |
| MethodDesc& md = irm.getMethodDesc(); |
| if (Log::isEnabled()) { |
| Log::out() << "Saw call to java/lang/Math::max from " |
| << md.getParentType()->getName() |
| << "::" |
| << md.getName() |
| << ::std::endl; |
| } |
| |
| Opnd *res = irBuilder.genMax(type, src0, src1); |
| if (res) { |
| pushOpnd(res); |
| return true; |
| } |
| |
| } else if (strcmp(methodName, "abs") == 0) { |
| assert(numArgs == 1); |
| Opnd *src0 = srcOpnds[0]; |
| Type *type = src0->getType(); |
| |
| IRManager& irm = *irBuilder.getIRManager(); |
| MethodDesc& md = irm.getMethodDesc(); |
| if (Log::isEnabled()) { |
| Log::out() << "Saw call to java/lang/Math::abs from " |
| << md.getParentType()->getName() |
| << "::" |
| << md.getName() |
| << ::std::endl; |
| } |
| |
| Opnd *res = irBuilder.genAbs(type, src0); |
| if (res) { |
| pushOpnd(res); |
| return true; |
| } |
| } else { |
| return false; |
| } |
| } |
| return false; |
| } |
| |
| //------------------------------------------------ |
| // synchronization helpers |
| //------------------------------------------------ |
| |
| void |
| JavaByteCodeTranslator::genMethodMonitorEnter() { |
| if (translationFlags.ignoreSync) { |
| popOpnd(); |
| return; |
| } |
| if (translationFlags.syncAsEnterFence) { |
| irBuilder.genMonitorEnterFence(popOpnd()); |
| } |
| else if (! translationFlags.onlyBalancedSync) { |
| irBuilder.genMonitorEnter(popOpnd()); |
| } |
| else { |
| assert(lockAddr == NULL && oldLockValue == NULL); |
| Opnd * obj = popOpnd(); |
| Type * lockType = typeManager.getUInt16Type(); |
| Type * lockAddrType = typeManager.getManagedPtrType(lockType); |
| Type * oldValueType = typeManager.getInt32Type(); |
| lockAddr = irBuilder.genLdLockAddr(lockAddrType,obj); |
| oldLockValue = irBuilder.genBalancedMonitorEnter(oldValueType,obj,lockAddr); |
| } |
| } |
| |
| void |
| JavaByteCodeTranslator::genMethodMonitorExit() { |
| if (translationFlags.ignoreSync || translationFlags.syncAsEnterFence) { |
| popOpnd(); |
| return; |
| } |
| |
| if (! translationFlags.onlyBalancedSync) { |
| irBuilder.genMonitorExit(popOpnd()); |
| } |
| else { |
| assert(lockAddr != NULL && oldLockValue != NULL); |
| irBuilder.genBalancedMonitorExit(popOpnd(),lockAddr,oldLockValue); |
| } |
| } |
| |
| U_32 JavaByteCodeTranslator::checkForArrayInitializer(Opnd* arrayOpnd, const U_8* byteCodes, U_32 offset, const U_32 byteCodeLength) |
| { |
| assert(offset < byteCodeLength); |
| const U_32 MIN_NUMBER_OF_INIT_ELEMS = 2; |
| |
| const U_8 BYTE_JAVA_SIZE = 1; |
| const U_8 SHORT_JAVA_SIZE = 2; |
| const U_8 INT_JAVA_SIZE = 4; |
| const U_8 LONG_JAVA_SIZE = 8; |
| |
| // Skip short array initializers. |
| // Average length of an array element initializer is 4. |
| if ((byteCodeLength - offset)/4 < MIN_NUMBER_OF_INIT_ELEMS) return 0; |
| |
| // Size of the array elements |
| U_8 elem_size = 0; |
| // Number of initialized array elements |
| U_32 elems = 0; |
| |
| ArrayType* arrayType = arrayOpnd->getType()->asArrayType(); |
| assert(arrayType); |
| Type* elemType = arrayType->getElementType(); |
| if (elemType->isBoolean() || elemType->isInt1()) { |
| elem_size = BYTE_JAVA_SIZE; |
| } else if (elemType->isInt2() || elemType->isChar()) { |
| elem_size = SHORT_JAVA_SIZE; |
| } else if (elemType->isInt4() || elemType->isSingle()) { |
| elem_size = INT_JAVA_SIZE; |
| } else if (elemType->isInt8() || elemType->isDouble()) { |
| elem_size = LONG_JAVA_SIZE; |
| } else { |
| assert(0); |
| } |
| |
| ::std::vector<uint64> array_data; |
| |
| // Current offset. |
| U_32 off = offset; |
| U_32 predoff = offset; |
| // Array element indexes |
| uint64 oldIndex = 0; |
| uint64 newIndex = 0; |
| // Array element value |
| uint64 value = 0; |
| |
| bool exitScan = false; |
| U_32 tmpOff = 0; |
| |
| while (byteCodes[off++] == 0x59/*dup*/) { |
| if (off >= byteCodeLength) break; |
| |
| // Get array element index |
| tmpOff = getNumericValue(byteCodes, off, byteCodeLength, newIndex); |
| if (!tmpOff || ((off += tmpOff) >= byteCodeLength)) break; |
| if (newIndex != (oldIndex++)) break; |
| |
| // Get array element value |
| tmpOff = getNumericValue(byteCodes, off, byteCodeLength, value); |
| if (!tmpOff || ((off += tmpOff) >= byteCodeLength)) break; |
| |
| // Store array element |
| switch (byteCodes[off++]) { |
| case 0x4f: // iastore |
| assert(elem_size == INT_JAVA_SIZE); |
| array_data.push_back((uint64)value); |
| break; |
| case 0x50: // lastore |
| assert(elem_size == LONG_JAVA_SIZE); |
| array_data.push_back((uint64)value); |
| break; |
| case 0x51: // fastore |
| assert(elem_size == INT_JAVA_SIZE); |
| array_data.push_back((uint64)value); |
| break; |
| case 0x52: // dastore |
| assert(elem_size == LONG_JAVA_SIZE); |
| array_data.push_back((uint64)value); |
| break; |
| case 0x54: // bastore |
| assert(elem_size == BYTE_JAVA_SIZE); |
| array_data.push_back((uint64)value); |
| break; |
| case 0x55: // castore |
| assert(elem_size == SHORT_JAVA_SIZE); |
| array_data.push_back((uint64)value); |
| break; |
| case 0x56: // sastore |
| assert(elem_size == SHORT_JAVA_SIZE); |
| array_data.push_back((uint64)value); |
| break; |
| default: |
| exitScan = true; |
| break; |
| } |
| if (exitScan || (off >= byteCodeLength)) break; |
| predoff = off; |
| elems++; |
| }/*end_while*/ |
| |
| if (elems < MIN_NUMBER_OF_INIT_ELEMS) return 0; |
| |
| const U_32 data_size = elems* elem_size; |
| U_8* init_array_data = new U_8[data_size]; |
| |
| for (U_32 i = 0; i < elems; i++) { |
| switch (elem_size) { |
| case BYTE_JAVA_SIZE: |
| init_array_data[i] = (U_8)(array_data[i]); |
| break; |
| case SHORT_JAVA_SIZE: |
| *((uint16*)(init_array_data + (i * SHORT_JAVA_SIZE))) = (uint16)(array_data[i]); |
| break; |
| case INT_JAVA_SIZE: |
| *((U_32*)(init_array_data + (i * INT_JAVA_SIZE))) = (U_32)(array_data[i]); |
| break; |
| case LONG_JAVA_SIZE: |
| *((uint64*)(init_array_data + (i * LONG_JAVA_SIZE))) = (uint64)(array_data[i]); |
| break; |
| default: |
| assert(0); |
| } |
| } |
| |
| Type* returnType = typeManager.getVoidType(); |
| Opnd* arrayDataOpnd = irBuilder.genLdConstant((POINTER_SIZE_SINT)init_array_data); |
| Opnd* arrayElemsOffset = irBuilder.genLdConstant((I_32)(arrayType->getArrayElemOffset())); |
| Opnd* elemsOpnd = irBuilder.genLdConstant((I_32)data_size); |
| |
| const U_32 numArgs = 4; |
| Opnd* args[numArgs] = {arrayOpnd, arrayElemsOffset, arrayDataOpnd, elemsOpnd}; |
| irBuilder.genJitHelperCall(InitializeArray, returnType, numArgs, args); |
| |
| |
| return predoff - offset; |
| } |
| |
| U_32 JavaByteCodeTranslator::getNumericValue(const U_8* byteCodes, U_32 offset, const U_32 byteCodeLength, uint64& value) { |
| assert(offset < byteCodeLength); |
| U_32 off = offset; |
| switch (byteCodes[off++]) { |
| case 0x02: // iconst_m1 |
| value = (uint64)(-1); |
| break; |
| case 0x03: // iconst_0 |
| case 0x09: // lconst_0 |
| value = 0; |
| break; |
| case 0x04: // iconst_1 |
| case 0x0a: // lconst_1 |
| value = 1; |
| break; |
| case 0x05: // iconst_2 |
| value = 2; |
| break; |
| case 0x06: // iconst_3 |
| value = 3; |
| break; |
| case 0x07: // iconst_4 |
| value = 4; |
| break; |
| case 0x08: // iconst_5 |
| value = 5; |
| break; |
| case 0x0b: // fconst_0 |
| { |
| float val = 0.0f; |
| value = (uint64)(*((U_32*)(&val))); |
| } |
| break; |
| case 0x0c: // fconst_1 |
| { |
| float val = 1.0f; |
| value = (uint64)(*((U_32*)(&val))); |
| } |
| break; |
| case 0x0d: // fconst_2 |
| { |
| float val = 2.0f; |
| value = (uint64)(*((U_32*)(&val))); |
| } |
| break; |
| case 0x0e: // dconst_0 |
| { |
| double val = 0.0; |
| value = *((uint64*)(&val)); |
| } |
| break; |
| case 0x0f: // dconst_1 |
| { |
| double val = 1.0; |
| value = *((uint64*)(&val)); |
| } |
| break; |
| case 0x10: // bipush |
| if (off >= byteCodeLength) return 0; |
| value = (uint64)si8(byteCodes + (off++)); |
| break; |
| case 0x11: // sipush |
| if ((off + 1) >= byteCodeLength) return 0; |
| value = (uint64)si16(byteCodes + off); |
| off += 2; |
| break; |
| case 0x12: // ldc |
| { |
| if (off >= byteCodeLength) return 0; |
| U_32 constPoolIndex = su8(byteCodes + (off++)); |
| // load 32-bit quantity from constant pool |
| Type* constantType = compilationInterface.getConstantType(&methodToCompile,constPoolIndex); |
| if ( !(constantType->isInt4() || constantType->isSingle()) ) { |
| // only integer and floating-point types |
| // are implemented for streamed array loads |
| return 0; |
| } |
| const void* constantAddress = |
| compilationInterface.getConstantValue(&methodToCompile,constPoolIndex); |
| value = *(U_32*)constantAddress; |
| } |
| break; |
| case 0x13: // ldc_w |
| { |
| if ((off + 1) >= byteCodeLength) return 0; |
| U_32 constPoolIndex = su16(byteCodes + off); |
| // load 32-bit quantity from constant pool |
| Type* constantType = compilationInterface.getConstantType(&methodToCompile,constPoolIndex); |
| if ( !(constantType->isInt4() || constantType->isSingle()) ) { |
| // only integer and floating-point types |
| // are implemented for streamed array loads |
| return 0; |
| } |
| const void* constantAddress = |
| compilationInterface.getConstantValue(&methodToCompile,constPoolIndex); |
| value = *(U_32*)constantAddress; |
| } |
| off += 2; |
| break; |
| case 0x14: // ldc2_w |
| { |
| if ((off + 1) >= byteCodeLength) return 0; |
| U_32 constPoolIndex = su16(byteCodes + off); |
| // load 64-bit quantity from constant pool |
| Type* constantType = compilationInterface.getConstantType(&methodToCompile,constPoolIndex); |
| if ( !(constantType->isInt8() || constantType->isDouble()) ) { |
| // only integer and floating-point types |
| // are implemented for streamed array loads |
| return 0; |
| } |
| const void* constantAddress = |
| compilationInterface.getConstantValue(&methodToCompile,constPoolIndex); |
| value = *(uint64*)constantAddress; |
| } |
| off += 2; |
| break; |
| default: |
| return 0; |
| } |
| return off - offset; |
| } |
| |
| bool JavaByteCodeTranslator::genVMMagic(const char* mname, U_32 numArgs, Opnd **srcOpnds, Type *magicRetType) { |
| Type* resType = convertVMMagicType2HIR(typeManager, magicRetType); |
| Type* cmpResType = typeManager.getInt32Type(); |
| Opnd* tauSafe = irBuilder.genTauSafe(); |
| Opnd* arg0 = numArgs > 0 ? srcOpnds[0]: NULL; |
| Opnd* arg1 = numArgs > 1 ? srcOpnds[1]: NULL; |
| Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No); |
| |
| |
| // max, one, zero |
| POINTER_SIZE_INT theConst = 0; |
| bool loadConst = false; |
| if (!strcmp(mname, "max")) { loadConst = true; theConst = ~(POINTER_SIZE_INT)0;} |
| else if (!strcmp(mname, "one")) { loadConst = true; theConst = 1;} |
| else if (!strcmp(mname, "zero")) { loadConst = true; theConst = 0;} |
| else if (!strcmp(mname, "nullReference")) { loadConst = true; theConst = 0;} |
| if (loadConst) { |
| ConstInst::ConstValue v; |
| #ifdef _EM64T_ |
| v.i8 = theConst; |
| #else |
| v.i4 = theConst; |
| #endif |
| Opnd* res = irBuilder.genLdConstant(typeManager.getUIntPtrType(), v); |
| |
| if (resType->isPtr()) { |
| res = irBuilder.genConv(resType, resType->tag, mod, res); |
| } |
| pushOpnd(res); |
| return true; |
| } |
| |
| // |
| // prefetch |
| // |
| if (!strcmp(mname, "prefetch")) |
| { |
| Opnd* prefetchingAddress = arg0; |
| irBuilder.genPrefetch(prefetchingAddress); |
| return true; |
| } |
| |
| // |
| // fromXXX, toXXX - static creation from something |
| // |
| if (!strcmp(mname, "fromLong") |
| || !strcmp(mname, "fromIntSignExtend") |
| || !strcmp(mname, "fromIntZeroExtend") |
| || !strcmp(mname, "fromObject") |
| || !strcmp(mname, "toAddress") |
| || !strcmp(mname, "toObjectReference") |
| || !strcmp(mname, "toInt") |
| || !strcmp(mname, "toLong") |
| || !strcmp(mname, "toObjectRef") |
| || !strcmp(mname, "toWord") |
| || !strcmp(mname, "toAddress") |
| || !strcmp(mname, "toObject") |
| || !strcmp(mname, "toExtent") |
| || !strcmp(mname, "toOffset")) |
| { |
| assert(numArgs == 1); |
| Type* srcType = arg0->getType(); |
| if (resType == srcType) { |
| pushOpnd(irBuilder.genCopy(arg0)); |
| return true; |
| } |
| Opnd* res = NULL; |
| |
| if ((srcType->isObject() && resType->isUnmanagedPtr()) |
| || (resType->isObject() && srcType->isUnmanagedPtr())) |
| { |
| res = irBuilder.genConvUnmanaged(resType, resType->tag, mod, arg0); |
| } else if (!strcmp(mname, "fromIntZeroExtend")) { |
| res = irBuilder.genConvZE(resType, resType->tag, mod, arg0); |
| } else { |
| res = irBuilder.genConv(resType, resType->tag, mod, arg0); |
| } |
| pushOpnd(res); |
| return true; |
| } |
| |
| // |
| // is<Smth> one arg testing |
| // |
| bool isOp = false; |
| if (!strcmp(mname, "isZero")) { isOp = true; theConst = 0; } |
| else if (!strcmp(mname, "isMax")) { isOp = true; theConst = ~(POINTER_SIZE_INT)0; } |
| else if (!strcmp(mname, "isNull")) { isOp = true; theConst = 0; } |
| if (isOp) { |
| assert(numArgs == 1); |
| Opnd* res = irBuilder.genCmp(cmpResType, arg0->getType()->tag, Cmp_EQ, arg0, irBuilder.genLdConstant((POINTER_SIZE_SINT)theConst)); |
| pushOpnd(res); |
| return true; |
| } |
| |
| |
| // |
| // EQ, GE, GT, LE, LT, sXX - 2 args compare |
| // |
| ComparisonModifier cm = Cmp_Mask; |
| bool commuteOpnds=false; |
| if (!strcmp(mname, "EQ")) { cm = Cmp_EQ; } |
| else if (!strcmp(mname, "equals")){ cm = Cmp_EQ; } |
| else if (!strcmp(mname, "NE")) { cm = Cmp_NE_Un; } |
| else if (!strcmp(mname, "GE")) { cm = Cmp_GTE_Un;} |
| else if (!strcmp(mname, "GT")) { cm = Cmp_GT_Un; } |
| else if (!strcmp(mname, "LE")) { cm = Cmp_GTE_Un; commuteOpnds = true;} |
| else if (!strcmp(mname, "LT")) { cm = Cmp_GT_Un; commuteOpnds = true;} |
| else if (!strcmp(mname, "sGE")) { cm = Cmp_GTE;} |
| else if (!strcmp(mname, "sGT")) { cm = Cmp_GT; } |
| else if (!strcmp(mname, "sLE")) { cm = Cmp_GTE; commuteOpnds = true;} |
| else if (!strcmp(mname, "sLT")) { cm = Cmp_GT; commuteOpnds = true;} |
| |
| if (cm!=Cmp_Mask) { |
| assert(numArgs == 2); |
| assert(arg0->getType() == arg1->getType()); |
| Opnd* op0 = commuteOpnds ? arg1 : arg0; |
| Opnd* op1 = commuteOpnds ? arg0 : arg1; |
| Opnd* res = irBuilder.genCmp(cmpResType, arg0->getType()->tag, cm, op0, op1); |
| pushOpnd(res); |
| return true; |
| } |
| |
| |
| // |
| // plus, minus, xor, or, and ... etc - 1,2 args arithmetics |
| // |
| if (!strcmp(mname, "plus")) { |
| assert(numArgs==2); |
| if (resType->isPtr()) { |
| pushOpnd(irBuilder.genAddScaledIndex(arg0, arg1)); |
| } else { |
| pushOpnd(irBuilder.genAdd(resType, mod, arg0, arg1)); |
| } |
| return true; |
| } |
| if (!strcmp(mname, "minus")){ |
| assert(numArgs==2); |
| if (resType->isPtr()) { |
| Type* negType = arg1->getType()->isUIntPtr() ? typeManager.getIntPtrType() : arg1->getType(); |
| Opnd* negArg1 = irBuilder.genNeg(negType, arg1); |
| pushOpnd(irBuilder.genAddScaledIndex(arg0, negArg1)); |
| } else { |
| pushOpnd(irBuilder.genSub(resType, mod, arg0, arg1)); |
| } |
| return true; |
| } |
| if (!strcmp(mname, "or")) { assert(numArgs==2); pushOpnd(irBuilder.genOr (resType, arg0, arg1)); return true;} |
| if (!strcmp(mname, "xor")) { assert(numArgs==2); pushOpnd(irBuilder.genXor(resType, arg0, arg1)); return true;} |
| if (!strcmp(mname, "and")) { assert(numArgs==2); pushOpnd(irBuilder.genAnd(resType, arg0, arg1)); return true;} |
| if (!strcmp(mname, "not")) { assert(numArgs==1); pushOpnd(irBuilder.genNot(resType, arg0)); return true;} |
| if (!strcmp(mname, "diff")) { assert(numArgs==2); pushOpnd(irBuilder.genSub(resType, mod, arg0, arg1)); return true;} |
| |
| |
| // |
| // shifts |
| // |
| Modifier shMod(ShiftMask_Masked); |
| if (!strcmp(mname, "lsh")) {assert(numArgs==2); pushOpnd(irBuilder.genShl(resType, shMod|SignedOp, arg0, arg1)); return true;} |
| else if (!strcmp(mname, "rsha")){assert(numArgs==2); pushOpnd(irBuilder.genShr(resType, shMod|SignedOp, arg0, arg1)); return true;} |
| else if (!strcmp(mname, "rshl")){assert(numArgs==2); pushOpnd(irBuilder.genShr(resType, shMod |UnsignedOp, arg0, arg1)); return true;} |
| |
| |
| // |
| // loadXYZ.. prepareXYZ.. |
| // |
| if (!strcmp(mname, "loadObjectReference") |
| || !strcmp(mname, "loadAddress") |
| || !strcmp(mname, "loadWord") |
| || !strcmp(mname, "loadByte") |
| || !strcmp(mname, "loadChar") |
| || !strcmp(mname, "loadDouble") |
| || !strcmp(mname, "loadFloat") |
| || !strcmp(mname, "loadInt") |
| || !strcmp(mname, "loadLong") |
| || !strcmp(mname, "loadShort") |
| || !strcmp(mname, "prepareWord") |
| || !strcmp(mname, "prepareObjectReference") |
| || !strcmp(mname, "prepareAddress") |
| || !strcmp(mname, "prepareInt")) |
| { |
| assert(numArgs == 1 || numArgs == 2); |
| Opnd* effectiveAddress = arg0; |
| if (numArgs == 2) {//load by offset |
| effectiveAddress = irBuilder.genAddScaledIndex(arg0, arg1); |
| } |
| Opnd* res = irBuilder.genTauLdInd(AutoCompress_No, resType, resType->tag, effectiveAddress, tauSafe, tauSafe); |
| pushOpnd(res); |
| return true; |
| } |
| |
| // |
| // store(XYZ) |
| // |
| if (!strcmp(mname, "store")) { |
| assert(numArgs==2 || numArgs == 3); |
| Opnd* effectiveAddress = arg0; |
| if (numArgs == 3) { // store by offset |
| effectiveAddress = irBuilder.genAddScaledIndex(arg0, srcOpnds[2]); |
| } |
| irBuilder.genTauStInd(arg1->getType(), effectiveAddress, arg1, tauSafe, tauSafe, tauSafe); |
| return true; |
| } |
| |
| if (!strcmp(mname, "attempt")) { |
| assert(numArgs == 3 || numArgs == 4); |
| Opnd* effectiveAddress = arg0; |
| if (numArgs == 4) { // offset opnd |
| effectiveAddress = irBuilder.genAddScaledIndex(arg0, srcOpnds[3]); |
| } |
| Opnd* opnds[3] = {effectiveAddress, arg1, srcOpnds[2]}; |
| Opnd* res = irBuilder.genJitHelperCall(LockedCompareAndExchange, resType, 3, opnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| // |
| //Arrays |
| // |
| if (!strcmp(mname, "create")) { assert(numArgs==1); pushOpnd(irBuilder.genNewArray(resType->asNamedType(),arg0)); return true;} |
| if (!strcmp(mname, "set")) { |
| assert(numArgs == 3); |
| Opnd* arg2 = srcOpnds[2]; |
| Type* opType = convertVMMagicType2HIR(typeManager, arg2->getType()); |
| irBuilder.genStElem(opType, arg0, arg1, arg2, tauSafe, tauSafe, tauSafe); |
| return true; |
| } |
| if (!strcmp(mname, "get")) { |
| assert(numArgs == 2); |
| Opnd* res = irBuilder.genLdElem(resType, arg0, arg1, tauSafe, tauSafe); |
| pushOpnd(res); |
| return true; |
| } |
| if (!strcmp(mname, "length")) { |
| pushOpnd(irBuilder.genArrayLen(typeManager.getInt32Type(), Type::Int32, arg0)); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool JavaByteCodeTranslator::genVMHelper(const char* mname, U_32 numArgs, Opnd **srcOpnds, Type *returnType) { |
| Type* resType = VMMagicUtils::isVMMagicClass(returnType->getName()) ? convertVMMagicType2HIR(typeManager, returnType) : returnType; |
| |
| //VMHelper methods |
| |
| if (!strcmp(mname,"getTlsBaseAddress")) { |
| assert(numArgs == 0); |
| Opnd* res = irBuilder.genVMHelperCall(VM_RT_GC_GET_TLS_BASE, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"newResolvedUsingAllocHandleAndSize")) { |
| assert(numArgs == 2); |
| Opnd* res = irBuilder.genVMHelperCall(VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"newVectorUsingAllocHandle")) { |
| assert(numArgs == 2); |
| Opnd* res = irBuilder.genVMHelperCall(VM_RT_NEW_VECTOR_USING_VTABLE, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"monitorEnter")) { |
| assert(numArgs == 1); |
| irBuilder.genVMHelperCall(VM_RT_MONITOR_ENTER, resType, numArgs, srcOpnds); |
| return true; |
| } |
| |
| if (!strcmp(mname,"monitorExit")) { |
| assert(numArgs == 1); |
| irBuilder.genVMHelperCall(VM_RT_MONITOR_EXIT, resType, numArgs, srcOpnds); |
| return true; |
| } |
| |
| if (!strcmp(mname,"writeBarrier")) { |
| assert(numArgs == 3); |
| irBuilder.genVMHelperCall(VM_RT_GC_HEAP_WRITE_REF, resType, numArgs, srcOpnds); |
| return true; |
| } |
| |
| if (!strcmp(mname, "memset0")) |
| { |
| assert(numArgs == 2); |
| irBuilder.genJitHelperCall(Memset0, resType, numArgs, srcOpnds); |
| return true; |
| } |
| |
| if (!strcmp(mname, "prefetch")) |
| { |
| assert(numArgs == 3); |
| irBuilder.genJitHelperCall(Prefetch, resType, numArgs, srcOpnds); |
| return true; |
| } |
| |
| if (!strcmp(mname,"getInterfaceVTable")) { |
| assert(numArgs == 2); |
| Opnd* res = irBuilder.genVMHelperCall(VM_RT_GET_INTERFACE_VTABLE_VER0, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"checkCast")) { |
| assert(numArgs == 2); |
| irBuilder.genVMHelperCall(VM_RT_CHECKCAST, resType, numArgs, srcOpnds); |
| return true; |
| } |
| |
| if (!strcmp(mname,"instanceOf")) { |
| assert(numArgs == 2); |
| Opnd* res = irBuilder.genVMHelperCall(VM_RT_INSTANCEOF, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| |
| //no VMHelpers exist for these magics -> use internal JIT helpers |
| |
| if (!strcmp(mname,"isArray")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassIsArray, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"getAllocationHandle")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassGetAllocationHandle, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"getTypeSize")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassGetTypeSize, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"getArrayElemSize")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassGetArrayElemSize, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"isInterface")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassIsInterface, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"isFinal")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassIsFinal, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"getArrayClass")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassGetArrayClass, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"isFinalizable")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassIsFinalizable, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"getFastTypeCheckDepth")) { |
| assert(numArgs == 1 && srcOpnds[0]->getType()->isUnmanagedPtr()); |
| Opnd* res = irBuilder.genJitHelperCall(ClassGetFastCheckDepth, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"isVMMagicPackageSupported")) { |
| assert(numArgs == 0); |
| ObjectType* base = compilationInterface.findClassUsingBootstrapClassloader(VMHELPER_TYPE_NAME); |
| int ready = base!=NULL && !base->needsInitialization() ? 1 : 0; |
| Opnd* res = irBuilder.genLdConstant((I_32)ready); |
| pushOpnd(res); |
| return true; |
| } |
| |
| if (!strcmp(mname,"getHashcode")) { |
| assert(numArgs == 1); |
| Opnd* res = irBuilder.genVMHelperCall(VM_RT_GET_IDENTITY_HASHCODE, resType, numArgs, srcOpnds); |
| pushOpnd(res); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| } //namespace Jitrino |