Index: vm/include/jit_import.h =================================================================== --- vm/include/jit_import.h (revision 612518) +++ vm/include/jit_import.h (working copy) @@ -28,6 +28,7 @@ #include "open/types.h" #include "open/vm.h" #include "jit_import_rt.h" +#include "vm_core_types.h" #ifdef __cplusplus extern "C" { @@ -584,6 +585,15 @@ VMEXPORT const void *class_get_const_addr(Class_Handle ch, unsigned idx); /** +* Looks for a method in native libraries of a class loader. +* +* @param[in] method - a searching native-method structure +* @return The pointer to found a native function. +* @note The function raises UnsatisfiedLinkError with a method name +* in an exception message, if the specified method is not found.*/ +VMEXPORT void* method_get_native_func_addr(Method_Handle method); + +/** * @return The JIT handle for a the current compilation. * * The VM keeps track of the JIT that was invoked for and can return this value at Index: vm/vmcore/build/vmcore.exp =================================================================== --- vm/vmcore/build/vmcore.exp (revision 612518) +++ vm/vmcore/build/vmcore.exp (working copy) @@ -273,6 +273,8 @@ Java_java_util_concurrent_locks_LockSupport_unpark; Java_org_apache_harmony_drlvm_thread_ThreadHelper_getThreadIdOffset; Java_org_apache_harmony_drlvm_thread_ThreadHelper_getLockWordOffset; + Java_org_apache_harmony_drlvm_thread_ThreadHelper_monitorEnterSlow; + Java_org_apache_harmony_drlvm_thread_ThreadHelper_monitorExitSlow; Java_org_apache_harmony_drlvm_VMHelperFastPath_getObjectVtableOffset; Java_org_apache_harmony_drlvm_VMHelperFastPath_getVtableClassOffset; Java_org_apache_harmony_drlvm_VMHelperFastPath_getVtableIntfTableOffset; @@ -508,6 +510,7 @@ method_get_max_stack; method_get_method_jit; method_get_name; + method_get_native_func_addr; method_get_next_method_jit; method_get_num_handlers; method_get_offset; Index: vm/vmcore/src/class_support/C_Interface.cpp =================================================================== --- vm/vmcore/src/class_support/C_Interface.cpp (revision 612518) +++ vm/vmcore/src/class_support/C_Interface.cpp (working copy) @@ -927,6 +927,9 @@ } //class_get_const_addr +void* method_get_native_func_addr(Method_Handle method) { + return (void*)classloader_find_native(method); +} Arg_List_Iterator method_get_argument_list(Method_Handle m) { Index: vm/jitrino/config/ia32/server_static.emconf =================================================================== --- vm/jitrino/config/ia32/server_static.emconf (revision 612518) +++ vm/jitrino/config/ia32/server_static.emconf (working copy) @@ -36,7 +36,7 @@ -XX:jit.SS_OPT.path.osr_path=simplify,dce,uce,gcm,osr -XX:jit.SS_OPT.path.escape_path=hvn,simplify,dce,uce,escape -XX:jit.SS_OPT.path.abce=classic_abcd,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,memopt,dce,uce,dessa,fastArrayFill,ssa,statprof,dabce,dce,uce --XX:jit.SS_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method +-XX:jit.SS_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,light_jni,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method -XX:jit.SS_OPT.path.dce1=cg_dce -XX:jit.SS_OPT.path.dce2=cg_dce Index: vm/jitrino/config/ia32/client.emconf =================================================================== --- vm/jitrino/config/ia32/client.emconf (revision 612518) +++ vm/jitrino/config/ia32/client.emconf (working copy) @@ -54,7 +54,7 @@ -XX:jit.CD_OPT.path=opt_init,lock_method,translator,optimizer,hir2lir,codegen,unlock_method -XX:jit.CD_OPT.path.optimizer=ssa,devirt,hlo_api_magic,inline,purge,simplify,dce,uce,lazyexc,throwopt,memopt,simplify,dce,uce,lower,statprof,unroll,ssa,simplify,dce,uce,dessa,statprof --XX:jit.CD_OPT.path.codegen=bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info +-XX:jit.CD_OPT.path.codegen=bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,light_jni,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info -XX:jit.CD_OPT.path.dce1=cg_dce -XX:jit.CD_OPT.path.dce2=cg_dce -XX:jit.CD_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 Index: vm/jitrino/config/ia32/opt.emconf =================================================================== --- vm/jitrino/config/ia32/opt.emconf (revision 612518) +++ vm/jitrino/config/ia32/opt.emconf (working copy) @@ -27,7 +27,7 @@ -XX:jit.CS_OPT.path.optimizer=ssa,devirt,hlo_api_magic,inline,purge,osr_path-,simplify,dce,uce,lazyexc,throwopt,escape_path,dce,uce,memopt,simplify,dce,uce,lower,statprof,unroll,ssa,simplify,dce,uce,dessa,statprof -XX:jit.CS_OPT.path.osr_path=simplify,dce,uce,gcm,osr -XX:jit.CS_OPT.path.escape_path=hvn,simplify,dce,uce,escape --XX:jit.CS_OPT.path.codegen=bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info +-XX:jit.CS_OPT.path.codegen=bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,light_jni,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info -XX:jit.CS_OPT.path.dce1=cg_dce -XX:jit.CS_OPT.path.dce2=cg_dce -XX:jit.CS_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 Index: vm/jitrino/config/ia32/server_aggressive.emconf =================================================================== --- vm/jitrino/config/ia32/server_aggressive.emconf (revision 612518) +++ vm/jitrino/config/ia32/server_aggressive.emconf (working copy) @@ -77,7 +77,7 @@ -XX:jit.SD2_OPT.path.escape_path=hvn,simplify,dce,uce,escape -XX:jit.SD2_OPT.path.abce=classic_abcd,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,memopt,dce,uce,dessa,fastArrayFill,ssa,statprof,dabce,dce,uce --XX:jit.SD2_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method +-XX:jit.SD2_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,light_jni,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method -XX:jit.SD2_OPT.path.dce1=cg_dce -XX:jit.SD2_OPT.path.dce2=cg_dce Index: vm/jitrino/config/ia32/server.emconf =================================================================== --- vm/jitrino/config/ia32/server.emconf (revision 612518) +++ vm/jitrino/config/ia32/server.emconf (working copy) @@ -83,7 +83,7 @@ -XX:jit.SD2_OPT.path.osr_path=simplify,dce,uce,gcm,osr -XX:jit.SD2_OPT.path.escape_path=hvn,simplify,dce,uce,escape -XX:jit.SD2_OPT.path.abce=classic_abcd,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,memopt,dce,uce,dessa,fastArrayFill,ssa,statprof,dabce,dce,uce --XX:jit.SD2_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method +-XX:jit.SD2_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,light_jni,early_prop,peephole,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,copy,i586,layout,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method -XX:jit.SD2_OPT.path.dce1=cg_dce -XX:jit.SD2_OPT.path.dce2=cg_dce Index: vm/jitrino/src/codegenerator/ia32/Ia32LightJNI.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32LightJNI.cpp (revision 0) +++ vm/jitrino/src/codegenerator/ia32/Ia32LightJNI.cpp (revision 0) @@ -0,0 +1,261 @@ +/* +* 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 Yuri Kashnikov +*/ + +#include "PMFAction.h" +#include "Ia32Inst.h" +#include "Ia32IRManager.h" +#include "methodtable.h" + + +//typedef std::map LightJNIOFMap; +#define PRAGMA_UNINTERRUPTIBLE "org/vmmagic/pragma/Uninterruptible" + +namespace Jitrino { +namespace Ia32{ + + + +class LightJNIAction: public Action { +public: + LightJNIAction():_myMM("LightJNIAction"){} + void init(); + Method_Table* getOFTable() { return lightJNIMethodTable;} +protected: + MemoryManager _myMM; + Method_Table* lightJNIMethodTable; +}; + + + +class LightJNISession : public SessionAction { +protected: + void runImpl(); + uint32 getSideEffects()const{ return 0; } + const char* getName() { return "light_jni"; } + bool isInOptimizationTable(Method_Table* table, MethodDesc* mmd); + void derefIfObject(CallInst* callInst, Opnd* origRetOpnd); + + CompilationContext* cc; + IRManager* lirm; + ControlFlowGraph* fg; + +}; + +ActionFactory light_jni("light_jni"); + +void LightJNIAction::init() +{ + const char* lightJNIMethods = getStringArg("light_jni_methods", NULL); + lightJNIMethodTable = new (_myMM) Method_Table(_myMM, lightJNIMethods, "LIGHTJNI_METHODS", false); + Method_Table::Decision des = Method_Table::mt_accepted; + + lightJNIMethodTable->add_method_record("java/lang/VMThreadManager", "currentThread", "()Ljava/lang/Thread;", des, false); + + // java/lang/Math + lightJNIMethodTable->add_method_record("java/lang/Math","cos","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","asin","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","acos","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","atan","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","atan2","(DD)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","cbrt","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","ceil","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","cos","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","cosh","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","exp","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","expm1","(D)D", des, false); + + lightJNIMethodTable->add_method_record("java/lang/Math","floor","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","hypot","(DD)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","IEEEremainder","(DD)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","log","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","log10","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","log1p","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","pow","(DD)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","rint","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","sin","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","sinh","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","sqrt","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","tan","(D)D", des, false); + lightJNIMethodTable->add_method_record("java/lang/Math","tanh","(D)D", des, false); + +} + + +bool LightJNISession::isInOptimizationTable(Method_Table* table, MethodDesc * mmd) +{ + + const char* className = mmd->getParentType()->getName(); + const char* methodName = mmd->getName(); + const char* sigName = mmd->getSignatureString(); + bool optResult = table->accept_this_method(className,methodName, sigName); + return optResult; +} + + +void LightJNISession::derefIfObject(CallInst* callInst, Opnd* origRetOpnd) +{ + Node* node = callInst->getNode(); + Type* origRetType = origRetOpnd->getType(); + Opnd* retOpnd = callInst->getOpnd(0); + if (callInst != node->getLastInst()) { + fg->splitNodeAtInstruction(callInst, true, true, NULL); + } + + node = callInst->getNode(); + Node* nextNode = node->getUnconditionalEdgeTarget(); + assert(nextNode!=NULL); + fg->removeEdge(node->getUnconditionalEdge()); + + Node* zeroObject = fg->createBlockNode(); + Node* nonZeroObject = fg->createBlockNode(); + + //TODO: EM64T! + Inst* cmpZeroInst = lirm->newInst(Mnemonic_CMP, retOpnd, lirm->newImmOpnd(retOpnd->getType(), 0)); + Inst* jumpZeroInst = lirm->newBranchInst(Mnemonic_JE, zeroObject, nonZeroObject); + // cmp eax, 0 ; eax = retOpnd + // je @zeroObject + cmpZeroInst->insertAfter(callInst); + jumpZeroInst->insertAfter(cmpZeroInst); + + // @zeroObject: + // mov eax,(NullObject)0 ; eax = retOpnd + Inst* movResZero = lirm->newInst(Mnemonic_MOV, origRetOpnd, lirm->newImmOpnd(lirm->getTypeManager().getNullObjectType(), 0)); + zeroObject->appendInst(movResZero); + + // @nonZeroObject: + // mov eax, [eax] ; eax = retOpnd + Inst* movResRes = lirm->newInst(Mnemonic_MOV, origRetOpnd, lirm->newMemOpndAutoKind(origRetType, retOpnd)); + nonZeroObject->appendInst(movResRes); + + // link nodes + fg->addEdge(node, nonZeroObject, 0.9); + fg->addEdge(node, zeroObject, 0.1); + fg->addEdge(zeroObject, nextNode); + fg->addEdge(nonZeroObject, nextNode); +} + +void LightJNISession::runImpl() { + LightJNIAction* action = (LightJNIAction*)getAction(); + Method_Table* tmpT = action->getOFTable(); + cc = getCompilationContext(); + MemoryManager tmpMM("tmp_lightjni_session"); + lirm = cc->getLIRManager(); + fg = lirm->getFlowGraph(); + NamedType* uninterruptiblePragma = NULL; + TypeManager& tm = lirm->getTypeManager(); + + // @Uninterruptible pragma + uninterruptiblePragma = lirm->getCompilationInterface().findClassUsingBootstrapClassloader(PRAGMA_UNINTERRUPTIBLE); + + StlVector callsToOptimize(tmpMM); + const Nodes& nodes = fg->getNodesPostOrder();//process checking only reachable nodes. + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { + if (!inst->hasKind(Inst::Kind_CallInst) || !((CallInst*)inst)->isDirect()) { + continue; + } + + CallInst* callInst = (CallInst*)inst; + Opnd * targetOpnd=callInst->getOpnd(callInst->getTargetOpndIndex()); + + assert(targetOpnd->isPlacedIn(OpndKind_Imm)); + Opnd::RuntimeInfo * ri=targetOpnd->getRuntimeInfo(); + if( !ri || ri->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) { + continue; + }; + + MethodDesc * md = (MethodDesc*)ri->getValue(0); + + if (!md->isNative()) { + continue; + } + if (!isInOptimizationTable(tmpT, md)) { + if (uninterruptiblePragma==NULL || !md->hasAnnotation(uninterruptiblePragma)){ + continue; + } + } + callsToOptimize.push_back(callInst); + } + } + } + + + for (StlVector::const_iterator it = callsToOptimize.begin(), end = callsToOptimize.end(); it!=end; ++it) { + CallInst* callInst = *it; + + Opnd * targetOpnd=callInst->getOpnd(callInst->getTargetOpndIndex()); + assert(targetOpnd->isPlacedIn(OpndKind_Imm)); + Opnd::RuntimeInfo * ri=targetOpnd->getRuntimeInfo(); + assert( ri && ri->getKind() == Opnd::RuntimeInfo::Kind_MethodDirectAddr); + MethodDesc * md = (MethodDesc*)ri->getValue(0); + +// printf("optimize %s::%s %s\n", md->getParentType()->getName(), md->getName(), md->getSignatureString()); + + void* tmpPoint = method_get_native_func_addr(md->getMethodHandle()); + Opnd* tmpZero = lirm->newImmOpnd(lirm->getTypeManager().getIntPtrType(), 0); + uint32 tmpNumArgs = callInst->getOpndCount(); + CallInst* newCallInst = NULL; + Opnd* origRetOpnd = callInst->getOpnd(0); + //const char* mmthName = md->getName(); + Opnd* newRetOpnd = origRetOpnd; + bool deref = origRetOpnd->getType()->isObject(); + if (deref) { + newRetOpnd = lirm->newOpnd(tm.getUnmanagedPtrType(tm.getUInt8Type())); + } + if (md->isInstance()){ + Opnd ** tmpOpnds = new (tmpMM) Opnd*[tmpNumArgs-1]; + Opnd* newTargetOpnd = lirm->newImmOpnd(tm.getIntPtrType(), ((POINTER_SIZE_INT)tmpPoint)); + + tmpOpnds[0] = tmpZero; + for (uint32 i = 2; igetOpnd(i); + } + newCallInst = lirm->newCallInst(newTargetOpnd, &CallingConvention_STDCALL, tmpNumArgs - 1, tmpOpnds, newRetOpnd); + } else { + assert(md->isStatic()); + Opnd ** tmpOpnds = new (tmpMM) Opnd*[tmpNumArgs]; + Opnd* newTargetOpnd = lirm->newImmOpnd(tm.getIntPtrType(), ((POINTER_SIZE_INT)tmpPoint)); + Opnd* tmpClassName = lirm->newImmOpnd(tm.getIntPtrType(), (POINTER_SIZE_INT)(md->getParentHandle())); + tmpOpnds[0] = tmpZero; + tmpOpnds[1] = tmpClassName; + for (uint32 i = 2; igetOpnd(i); + } + newCallInst = lirm->newCallInst(newTargetOpnd, &CallingConvention_STDCALL, tmpNumArgs, tmpOpnds, newRetOpnd); + } + + newCallInst->setBCOffset(callInst->getBCOffset()); + newCallInst->insertBefore(callInst); + callInst->unlink(); + + if (deref) { + derefIfObject(newCallInst, origRetOpnd); + } + + if (Log::isEnabled()) { + Log::out() << "changing for method" << md->getParentType()->getName() << "_" << md->getName() << "_" << md->getSignatureString() << std::endl; + } + } +} +}} //namespace +