Index: vm/vmcore/include/stack_trace.h =================================================================== --- vm/vmcore/include/stack_trace.h (revision 593520) +++ vm/vmcore/include/stack_trace.h (working copy) @@ -87,11 +87,10 @@ VMEXPORT unsigned st_get_depth(VM_thread *p_vmthread); /** - * Fills the stack trace frame at the given depth for the current thread. + * Fills the stack trace frame at the given relative depth for the current thread. * - * @param[in] depth - the zero-based depth of the frame or inlined method, - * information about which will be stored at the given stack trace - * frame, stf + * @param[in] depth - relative depth of a frame or inlined method on the stack, + * topmost frame has zero depth. * @param[out] stf - the pointer to the StackTraceFrame structure that needs * to be filled with the data on the frame or inlined method * corresponding to the given depth @@ -135,7 +134,7 @@ * * @param[in] method - the handle of the method information to identify the source file * @param[in] ip - the instruction pointer to identify the JIT and using the JIT line number - * @param[in] depth - the inlined depth for inlined methods, starting from 0; + * @param[in] depth - the inlined depth for inlined methods; * (-1) for native methods and methods which were not inlined * @param[out] file - the pointer to the file reference to be filled by this function * @param[out] line - the pointer to the line number to be filled by this function Index: vm/vmcore/include/jit_export_rt.h =================================================================== --- vm/vmcore/include/jit_export_rt.h (revision 593520) +++ vm/vmcore/include/jit_export_rt.h (working copy) @@ -192,12 +192,51 @@ GC_Enumeration_Handle enum_handle, JitFrameContext* context ); - +/** + * Returns number of methods which were inlined at the specified location (zero if none) + * @param jit - a JIT which produced the code + * @param prt - corresponding inline info + * @param offset - offset in native code relative to code block start + */ JITEXPORT uint32 JIT_get_inline_depth(JIT_Handle jit, InlineInfoPtr ptr, uint32 offset); +/** +* Returns specified inlined method (null if not found). +* The inlined methods are indexed as [max_depth..1], +* so the topmost method on the stack has maximum inline depth and +* enclosing methods have descending indicies. +* Zero depth would mean nearest non-inlined method and should not be used here. +* @param jit - a JIT which produced the code +* @param prt - corresponding inline info +* @param offset - offset in native code relative to code block start +* @param inline_depth - index of the inlined method +*/ +JITEXPORT Method_Handle +JIT_get_inlined_method(JIT_Handle jit, + InlineInfoPtr ptr, + uint32 offset, + uint32 inline_depth); + +/** +* Returns bytecode offset at specified inlined method for the native code (zero if unknown). +* The inlined methods are indexed as [max_depth..1], +* so the topmost method on the stack has maximum inline depth and +* enclosing methods have descending indicies. +* Zero depth would mean nearest non-inlined method and should not be used here. +* @param jit - a JIT which produced the code +* @param prt - corresponding inline info +* @param offset - offset in native code relative to code block start +* @param inline_depth - index of the inlined method +*/ +JITEXPORT uint16 +JIT_get_inlined_bc(JIT_Handle jit, + InlineInfoPtr ptr, + uint32 offset, + uint32 inline_depth); + JITEXPORT Boolean JIT_can_enumerate(JIT_Handle jit, Method_Handle method, Index: vm/vmcore/src/gc/root_set_enum_common.cpp =================================================================== --- vm/vmcore/src/gc/root_set_enum_common.cpp (revision 593520) +++ vm/vmcore/src/gc/root_set_enum_common.cpp (working copy) @@ -319,14 +319,16 @@ JIT *jit = cci->get_jit(); NativeCodePtr ip = si_get_ip(si); uint32 inlined_depth = si_get_inline_depth(si); - uint32 offset = (uint32)((POINTER_SIZE_INT)ip - (POINTER_SIZE_INT)cci->get_code_block_addr()); - for (uint32 i = 0; i < inlined_depth; i++) { - Method* m = jit->get_inlined_method(cci->get_inline_info(), offset, i); - assert (m); - cl = m->get_class()->get_class_loader(); - assert (cl); - // force cl classloader to be enumerated as strong reference - cl->Mark(); + if (inlined_depth) { + uint32 offset = (uint32)((POINTER_SIZE_INT)ip - (POINTER_SIZE_INT)cci->get_code_block_addr()); + for (uint32 i = inlined_depth; i > 0; i--) { + Method* m = jit->get_inlined_method(cci->get_inline_info(), offset, i); + assert (m); + cl = m->get_class()->get_class_loader(); + assert (cl); + // force cl classloader to be enumerated as strong reference + cl->Mark(); + } } } TRACE2("enumeration", "enumerated eip=" << (void *) si_get_ip(si) Index: vm/vmcore/src/jvmti/jvmti_stack.cpp =================================================================== --- vm/vmcore/src/jvmti/jvmti_stack.cpp (revision 593520) +++ vm/vmcore/src/jvmti/jvmti_stack.cpp (working copy) @@ -153,19 +153,21 @@ CodeChunkInfo *cci = si_get_code_chunk_info(si); JIT *jit = cci->get_jit(); + uint16 bc; // inlined method frame if (0 != inlined_depth) { uint32 offset = (uint32) ((char*) ip - (char*) cci->get_code_block_addr()); method = jit->get_inlined_method( - cci->get_inline_info(), offset, inlined_num - inlined_depth); + cci->get_inline_info(), offset, inlined_depth); + bc = jit->get_inlined_bc( + cci->get_inline_info(), offset, inlined_depth); + } else { + OpenExeJpdaError UNREF result = jit->get_bc_location_for_native( + method, ip, &bc); + assert(result == EXE_ERROR_NONE); } - uint16 bc; - OpenExeJpdaError UNREF result = jit->get_bc_location_for_native( - method, ip, &bc); - assert(result == EXE_ERROR_NONE); - *p_method = (jmethodID) method; *p_location = (jlocation) bc; } Index: vm/vmcore/src/stack/stack_trace.cpp =================================================================== --- vm/vmcore/src/stack/stack_trace.cpp (revision 593520) +++ vm/vmcore/src/stack/stack_trace.cpp (working copy) @@ -19,6 +19,10 @@ * @version $Revision: 1.1.2.1.4.3 $ */ +#define LOG_DOMAIN "vm.stack" +#include "cxxlog.h" +#include "vm_log.h" + #include "m2n.h" #include "stack_iterator.h" #include "stack_trace.h" @@ -47,8 +51,6 @@ return; } - // inlined method will not have line numbers for now - // they are marked with zero ip address. if (ip == NULL) { return; } @@ -65,6 +67,7 @@ POINTER_SIZE_INT eff_ip = (POINTER_SIZE_INT)ip - (is_ip_past ? callLength : 0); + uint32 offset = 0; if (depth < 0) // Not inlined method { if (cci->get_jit()->get_bc_location_for_native( @@ -77,13 +80,15 @@ if (inl_info) { - uint32 offset = (uint32) ((POINTER_SIZE_INT)ip - + offset = (uint32) ((POINTER_SIZE_INT)ip - (POINTER_SIZE_INT)cci->get_code_block_addr()); bcOffset = cci->get_jit()->get_inlined_bc(inl_info, offset, depth); } } *line = method->get_line_number(bcOffset); + TRACE("Location of " << method << " at idepth=" << depth << " noff=" << offset + << " bc=" << bcOffset << " line=" << *line); #endif } @@ -108,6 +113,7 @@ return interpreter.interpreter_st_get_frame(target_depth, stf); } + TRACE("looking for frame: "<ip = si_get_ip(si); - if (target_depth < depth + inlined_depth) { + if (target_depth != depth + inlined_depth) { + assert(inlined_depth); CodeChunkInfo* cci = si_get_code_chunk_info(si); // FIXME64: no support for large methods // with compiled code size greater than 4GB uint32 offset = (uint32)((POINTER_SIZE_INT)stf->ip - (POINTER_SIZE_INT)cci->get_code_block_addr()); + stf->depth = inlined_depth - (target_depth - depth); stf->method = cci->get_jit()->get_inlined_method( - cci->get_inline_info(), offset, target_depth - depth); - stf->depth = target_depth - depth; + cci->get_inline_info(), offset, stf->depth); + TRACE("found inlined frame: "<method << " at depth="<depth << " of "<< inlined_depth); } + else { + TRACE("found frame: "<method); + } si_free(si); return true; @@ -181,22 +192,28 @@ stf->outdated_this = 0; } else { JIT *jit = cci->get_jit(); - uint32 inlined_depth = si_get_inline_depth(si); - // FIXME64: no support for large methods - // with compiled code greater than 4GB - uint32 offset = (uint32)((POINTER_SIZE_INT)ip - (POINTER_SIZE_INT)cci->get_code_block_addr()); - - for (uint32 i = 0; i < inlined_depth; i++) { - stf->method = jit->get_inlined_method(cci->get_inline_info(), offset, i); - stf->ip = ip; - stf->depth = i; - stf->outdated_this = get_this(jit, method, si); - stf++; - depth++; + if (cci->has_inline_info()) { + // FIXME64: no support for large methods + // with compiled code greater than 4GB + uint32 offset = (uint32)((POINTER_SIZE_INT)ip - (POINTER_SIZE_INT)cci->get_code_block_addr()); + uint32 inlined_depth = jit->get_inline_depth( + cci->get_inline_info(), offset); + if (inlined_depth) { + for (uint32 i = inlined_depth; i > 0; i--) { + stf->method = jit->get_inlined_method(cci->get_inline_info(), offset, i); + stf->ip = ip; + stf->depth = i; + TRACE("tracing inlined frame: "<method << " at depth="<depth); + stf->outdated_this = get_this(jit, method, si); + stf++; + depth++; + } + } } stf->outdated_this = get_this(jit, method, si); } stf->method = method; + TRACE("tracing frame: "<method); stf->ip = ip; stf->depth = -1; stf++; @@ -282,17 +299,19 @@ if (m) { fprintf(f, " [%p] %p(%c): ", vm_thread, si_get_ip(si), (si_is_native(si) ? 'n' : 'm')); CodeChunkInfo* cci = si_get_code_chunk_info(si); - if ( cci != NULL ) { - uint32 inlined_depth = si_get_inline_depth(si); + if (cci != NULL && cci->has_inline_info()) { // FIXME64: no support for large methods // with compiled code size greater than 4GB uint32 offset = (uint32)((POINTER_SIZE_INT)si_get_ip(si) - (POINTER_SIZE_INT)cci->get_code_block_addr()); - - for (uint32 i = 0; i < inlined_depth; i++) { - Method *real_method = cci->get_jit()->get_inlined_method(cci->get_inline_info(), offset, i); - fprintf(f, "%s.%s%s\n", class_get_name(method_get_class(real_method)), - method_get_name(real_method), method_get_descriptor(real_method)); - depth++; + uint32 inlined_depth = cci->get_jit()->get_inline_depth( + cci->get_inline_info(), offset); + if (inlined_depth) { + for (uint32 i = inlined_depth; i > 0; i--) { + Method *real_method = cci->get_jit()->get_inlined_method(cci->get_inline_info(), offset, i); + fprintf(f, "%s.%s%s\n", class_get_name(method_get_class(real_method)), + method_get_name(real_method), method_get_descriptor(real_method)); + depth++; + } } } fprintf(f, "%s.%s%s\n", class_get_name(method_get_class(m)), method_get_name(m), method_get_descriptor(m)); Index: vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.cpp (revision 593520) +++ vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.cpp (working copy) @@ -127,7 +127,9 @@ uint32 RuntimeInterface::getInlineDepth(InlineInfoPtr ptr, uint32 offset) { const InlineInfoMap::Entry* e = InlineInfoMap::getEntryWithMaxDepth(ptr, offset); - return e == NULL ? 0 : e->getInlineDepth(); + // real instructions are recorded at an extra nested level to enclosing method + // but we need to count method marker entries only + return e == NULL ? 0 : e->getInlineDepth() - 1; } Method_Handle RuntimeInterface::getInlinedMethod(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { @@ -136,8 +138,26 @@ } uint16 RuntimeInterface::getInlinedBc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { - const InlineInfoMap::Entry* e = InlineInfoMap::getEntry(ptr, offset, inline_depth); - return e == NULL ? 0 : e->bcOffset; + const InlineInfoMap::Entry* e = InlineInfoMap::getEntryWithMaxDepth(ptr, offset); + assert(inline_depth); + + // Real instructions are recorded at a nested level to enclosing method + // and may happen on topmost entry only; + // otherwise we have a chain of inlined methods + // and each entry holds bcOffset of a call inst in parent method. + // Either way needed bcOffset is recorded at child entry + const InlineInfoMap::Entry* childCallee = e; + while (e) { + uint32 depth = e->getInlineDepth(); + if (depth == inline_depth) + { + return childCallee->bcOffset; + } + childCallee = e; + e = e->parentEntry; + } + + return 0; } Index: vm/jitrino/src/codegenerator/ia32/Ia32CodeEmitter.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32CodeEmitter.cpp (revision 593520) +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeEmitter.cpp (working copy) @@ -341,7 +341,7 @@ for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { if (inst->getKind() == Inst::Kind_MethodEntryPseudoInst) { if (Log::isEnabled()) { - IRPrinter::printIndent(Log::out(), parentEntry ? parentEntry->getInlineDepth() + 1 : 0); + IRPrinter::printIndent(Log::out(), parentEntry ? parentEntry->getInlineDepth() + 1 : 1); IRPrinter::printInst(Log::out(), inst); Log::out()<<" bc offset="<getBCOffset()<getInlineDepth(); + return (parentEntry == 0) ? 1 : 1 + parentEntry->getInlineDepth(); } }; Index: vm/jitrino/src/optimizer/CodeGenerator.cpp =================================================================== --- vm/jitrino/src/optimizer/CodeGenerator.cpp (revision 593520) +++ vm/jitrino/src/optimizer/CodeGenerator.cpp (working copy) @@ -146,6 +146,7 @@ header++; if (nativeOffset == nativeOffs) { Entry* e = (Entry*)((char*)ptr + entryOffset); + assert(e->getInlineDepth() > 1); return e; } } Index: vm/jitrino/src/optimizer/inliner.cpp =================================================================== --- vm/jitrino/src/optimizer/inliner.cpp (revision 593520) +++ vm/jitrino/src/optimizer/inliner.cpp (working copy) @@ -525,18 +525,16 @@ entry->getFirstInst()->unlink(); entry->prependInst(_instFactory.makeLabel()); - uint16 bcOffset = inlineNode->getCallInst()->getBCOffset(); - assert(bcOffset!=ILLEGAL_BC_MAPPING_VALUE); + uint16 callerOffset = inlineNode->getCallInst()->getBCOffset(); + assert(callerOffset!=ILLEGAL_BC_MAPPING_VALUE); Inst* entryMarker = obj ? _instFactory.makeMethodMarker(MethodMarkerInst::Entry, &methodDesc, obj) : _instFactory.makeMethodMarker(MethodMarkerInst::Entry, &methodDesc); - entryMarker->setBCOffset(bcOffset); + entryMarker->setBCOffset(callerOffset); entry->prependInst(entryMarker); - Node* retNode = inlinedFlowGraph.getReturnNode(); if (retNode) { Inst* exitMarker = obj ? _instFactory.makeMethodMarker(MethodMarkerInst::Exit, &methodDesc, obj) : _instFactory.makeMethodMarker(MethodMarkerInst::Exit, &methodDesc); - exitMarker->setBCOffset(entryMarker->getBCOffset()); retNode->appendInst(exitMarker); } @@ -544,7 +542,6 @@ if (unwindNode) { Inst* exitMarker = obj ? _instFactory.makeMethodMarker(MethodMarkerInst::Exit, &methodDesc, obj) : _instFactory.makeMethodMarker(MethodMarkerInst::Exit, &methodDesc); - exitMarker->setBCOffset(entryMarker->getBCOffset()); unwindNode->appendInst(exitMarker); } } Index: vm/jitrino/src/vm/JITInterface.cpp =================================================================== --- vm/jitrino/src/vm/JITInterface.cpp (revision 593520) +++ vm/jitrino/src/vm/JITInterface.cpp (working copy) @@ -419,6 +419,10 @@ if (Log::cat_rt()->isEnabled()) { Log::cat_rt()->out() << "GET_INLINED_METHOD()" << ::std::endl; } + if (0 == inline_depth) { + assert(0 && "misused inline_depth, must be [1..max_depth]"); + return 0; + } return Jitrino::GetInlinedMethod(ptr, offset, inline_depth); } @@ -429,6 +433,10 @@ if (Log::cat_rt()->isEnabled()) { Log::cat_rt()->out() << "GET_INLINED_BC()" << ::std::endl; } + if (0 == inline_depth) { + assert(0 && "misused inline_depth, must be [1..max_depth]"); + return 0; + } return Jitrino::GetInlinedBc(ptr, offset, inline_depth); } Index: vm/jitrino/src/main/Jitrino.cpp =================================================================== --- vm/jitrino/src/main/Jitrino.cpp (revision 593520) +++ vm/jitrino/src/main/Jitrino.cpp (working copy) @@ -286,21 +286,13 @@ Method_Handle Jitrino::GetInlinedMethod(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { - //+1 here because VM counts inlined methods range like: [0...max_depth) - //where 0 is the first inlined frame. - //but Jitrino.OPT algorithm counts methods like [0...max_depth] - //where 0 is an original method - return runtimeInterface->getInlinedMethod(ptr, offset, inline_depth+1); + return runtimeInterface->getInlinedMethod(ptr, offset, inline_depth); } uint16 Jitrino::GetInlinedBc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { - //+1 here because VM counts inlined methods range like: [0...max_depth) - //where 0 is the first inlined frame. - //but Jitrino.OPT algorithm counts methods like [0...max_depth] - //where 0 is an original method - return runtimeInterface->getInlinedBc(ptr, offset, inline_depth + 1); + return runtimeInterface->getInlinedBc(ptr, offset, inline_depth); } bool