diff --git a/pkg/dart2bytecode/lib/bytecode_generator.dart b/pkg/dart2bytecode/lib/bytecode_generator.dart index 05dd7d38be2..24252bc9a30 100644 --- a/pkg/dart2bytecode/lib/bytecode_generator.dart +++ b/pkg/dart2bytecode/lib/bytecode_generator.dart @@ -2282,12 +2282,12 @@ class BytecodeGenerator extends RecursiveVisitor { } } - // The CheckStack below is the instruction which should be used for function - // entry breakpoints. - _recordInitialSourcePositionForFunction(node, function); // CheckStack must see a properly initialized context when stress-testing // stack trace collection. asm.emitCheckStack(0); + // After checking the stack, the next instruction is safe for setting + // the entry breakpoint for a function. + _emitSourcePositionForFunctionEntryBreakpoint(node, function); if (locals.hasFunctionTypeArgsVar && isClosure) { if (function!.typeParameters.isNotEmpty) { @@ -2386,26 +2386,25 @@ class BytecodeGenerator extends RecursiveVisitor { } } - int _initialSourcePositionForFunction(TreeNode node, FunctionNode? function) { - // The debugger expects the initial source position to correspond to the - // declaration position of the last parameter, if any, or of the function. - if (function?.namedParameters.isNotEmpty ?? false) { - return function!.namedParameters.last.fileOffset; - } else if (function?.positionalParameters.isNotEmpty ?? false) { - return function!.positionalParameters.last.fileOffset; - } else if (function != null) { - return function.fileOffset; - } else { - return node.fileOffset; - } - } - - void _recordInitialSourcePositionForFunction( + void _emitSourcePositionForFunctionEntryBreakpoint( TreeNode node, FunctionNode? function, ) { - final position = _initialSourcePositionForFunction(node, function); - _recordSourcePosition(position, 0); + // The debugger expects the source position for function entry to correspond + // to the declaration position of the last parameter, if any, otherwise + // the file offset of the function. + final int startOffset; + if (function?.namedParameters.isNotEmpty ?? false) { + startOffset = function!.namedParameters.last.fileOffset; + } else if (function?.positionalParameters.isNotEmpty ?? false) { + startOffset = function!.positionalParameters.last.fileOffset; + } else if (function != null) { + startOffset = function.fileOffset; + } else { + startOffset = node.fileOffset; + } + _recordSourcePosition(startOffset, 0); + asm.emitSourcePosition(); } void _copyParamIfCaptured(VariableDeclaration variable) { diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status index b2b5733fd62..10c2a424592 100644 --- a/runtime/tests/vm/vm.status +++ b/runtime/tests/vm/vm.status @@ -91,6 +91,7 @@ cc/DeoptimizeFramesWhenSettingBreakpoint: SkipByDesign # JIT compilation is not cc/DerivedInduction: SkipByDesign # Building flow graph is not supported from bytecode. cc/Ffi_StructSinking: SkipByDesign # Building flow graph is not supported from bytecode. cc/FlowGraph_PhiUnboxingHeuristic_*: SkipByDesign # Building flow graph is not supported from bytecode. +cc/FullSnapshot: SkipByDesign # JIT compilation is not supported from bytecode. cc/IRTest_*: SkipByDesign # Building flow graph is not supported from bytecode. cc/Inliner_*: SkipByDesign # Building flow graph is not supported from bytecode. cc/IsolateReload_EnumWithSet: SkipByDesign # Bytecode doesn't support KernelProgramInfo. @@ -103,6 +104,7 @@ cc/NotEqualCondition*: SkipByDesign # Building flow graph is not supported from cc/OptimizeCompileFunctionOnHelperThread: SkipByDesign # JIT compilation is not supported from bytecode. cc/PeriodicAndDerived: SkipByDesign # Building flow graph is not supported from bytecode. cc/RangeAnalysis_*: SkipByDesign # Building flow graph is not supported from bytecode. +cc/ReachabilityFence_*: SkipByDesign # Building flow graph is not supported from bytecode. cc/SecondExit*: SkipByDesign # Building flow graph is not supported from bytecode. cc/StackMapGC: SkipByDesign # JIT compilation is not supported from bytecode. cc/StreamingFlowGraphBuilder_*: SkipByDesign # Building flow graph is not supported from bytecode. diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc index 22174eee008..82ea4dbe34a 100644 --- a/runtime/vm/benchmark_test.cc +++ b/runtime/vm/benchmark_test.cc @@ -272,18 +272,15 @@ static void StackFrame_accessFrame(Dart_NativeArguments args) { Thread* thread = Thread::Current(); TransitionNativeToVM transition(thread); const int kNumIterations = 100; - Code& code = Code::Handle(thread->zone()); for (int i = 0; i < kNumIterations; i++) { StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread, StackFrameIterator::kNoCrossThreadIteration); StackFrame* frame = frames.NextFrame(); while (frame != nullptr) { if (frame->IsStubFrame()) { - code = frame->LookupDartCode(); - EXPECT(code.function() == Function::null()); + EXPECT(frame->LookupDartFunction() == Function::null()); } else if (frame->IsDartFrame()) { - code = frame->LookupDartCode(); - EXPECT(code.function() != Function::null()); + EXPECT(frame->LookupDartFunction() != Function::null()); } frame = frames.NextFrame(); } diff --git a/runtime/vm/bytecode_reader.cc b/runtime/vm/bytecode_reader.cc index dc3181f51eb..715a34730ab 100644 --- a/runtime/vm/bytecode_reader.cc +++ b/runtime/vm/bytecode_reader.cc @@ -2425,6 +2425,10 @@ void BytecodeReaderHelper::ReadClassDeclaration(const Class& cls) { if (!cls.is_type_finalized()) { ClassFinalizer::FinalizeTypesInClass(cls); } + +#if !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER) + cls.SetUserVisibleNameInClassTable(); +#endif } void BytecodeReaderHelper::ReadLibraryDeclaration(const Library& library, diff --git a/runtime/vm/compiler/assembler/disassembler_kbc.cc b/runtime/vm/compiler/assembler/disassembler_kbc.cc index bb01f5fe204..86fba501a11 100644 --- a/runtime/vm/compiler/assembler/disassembler_kbc.cc +++ b/runtime/vm/compiler/assembler/disassembler_kbc.cc @@ -365,8 +365,6 @@ void KernelBytecodeDisassembler::Disassemble(uword start, char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. uword pc = start; - GrowableArray inlined_functions; - GrowableArray token_positions; while (pc < end) { int instruction_length; Object* object; diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index 7389c1529f7..59b622ca2f7 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -578,7 +578,7 @@ intptr_t ActivationFrame::DeoptId() { intptr_t ActivationFrame::LineNumber() { // Compute line number lazily since it causes scanning of the script. - const TokenPosition& token_pos = TokenPos(); + const TokenPosition& token_pos = TokenPos().ToRealIfSynthetic(); if ((line_number_ < 0) && token_pos.IsReal()) { const Script& script = Script::Handle(SourceScript()); script.GetTokenLocation(token_pos, &line_number_, &column_number_); @@ -588,7 +588,7 @@ intptr_t ActivationFrame::LineNumber() { intptr_t ActivationFrame::ColumnNumber() { // Compute column number lazily since it causes scanning of the script. - const TokenPosition& token_pos = TokenPos(); + const TokenPosition& token_pos = TokenPos().ToRealIfSynthetic(); if ((column_number_ < 0) && token_pos.IsReal()) { const Script& script = Script::Handle(SourceScript()); script.GetTokenLocation(token_pos, &line_number_, &column_number_); @@ -2063,36 +2063,42 @@ DebuggerStackTrace* DebuggerStackTrace::From(const class StackTrace& ex_trace) { // pre-allocated trace (such as a stack overflow) or (b) because a stack has // fewer frames that the pre-allocated trace (such as memory exhaustion with // a shallow stack). - if (!code_object.IsNull()) { - code ^= code_object.ptr(); + function = Function::null(); + uword start = 0; + bool is_optimized_code = false; + if (code_object.IsCode()) { + const auto& code = Code::Cast(code_object); ASSERT(code.IsFunctionCode()); function = code.function(); - if (function.is_visible()) { + start = code.PayloadStart(); + is_optimized_code = code.is_optimized(); + } else if (code_object.IsBytecode()) { + const auto& bytecode = Bytecode::Cast(code_object); + function = bytecode.function(); + start = bytecode.PayloadStart(); + } + if (function.IsNull() || !function.is_visible()) continue; + const uword pc = start + ex_trace.PcOffsetAtFrame(i); + if (is_optimized_code && ex_trace.expand_inlined()) { + // Traverse inlined frames. + code ^= code_object.ptr(); + for (InlinedFunctionsIterator it(code, pc); !it.Done(); it.Advance()) { + function = it.function(); + code = it.code(); ASSERT(function.ptr() == code.function()); - uword pc = code.PayloadStart() + ex_trace.PcOffsetAtFrame(i); - if (code.is_optimized() && ex_trace.expand_inlined()) { - // Traverse inlined frames. - for (InlinedFunctionsIterator it(code, pc); !it.Done(); - it.Advance()) { - function = it.function(); - code = it.code(); - ASSERT(function.ptr() == code.function()); - uword pc = it.pc(); - ASSERT(pc != 0); - ASSERT(code.PayloadStart() <= pc); - ASSERT(pc < (code.PayloadStart() + code.Size())); + uword pc = it.pc(); + ASSERT(pc != 0); + ASSERT(code.PayloadStart() <= pc); + ASSERT(pc < (code.PayloadStart() + code.Size())); - ActivationFrame* activation = new ActivationFrame( - pc, fp, sp, function, code, deopt_frame, deopt_frame_offset); - stack_trace->AddActivation(activation); - } - } else { - ActivationFrame* activation = new ActivationFrame( - pc, fp, sp, function, code, deopt_frame, deopt_frame_offset); - stack_trace->AddActivation(activation); - } + auto* const activation = new ActivationFrame( + pc, fp, sp, function, code, deopt_frame, deopt_frame_offset); + stack_trace->AddActivation(activation); } } + auto* const activation = new ActivationFrame( + pc, fp, sp, function, code_object, deopt_frame, deopt_frame_offset); + stack_trace->AddActivation(activation); } return stack_trace; } diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 2d611879f7b..2104245e2d4 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -6010,7 +6010,9 @@ void Class::set_user_name(const String& value) const { #endif // !defined(PRODUCT) #if !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER) -void Class::SetUserVisibleNameInClassTable() { +void Class::SetUserVisibleNameInClassTable() const { + // Top level classes don't record a user visible name in the class table. + if (IsTopLevel()) return; IsolateGroup* isolate_group = IsolateGroup::Current(); auto class_table = isolate_group->class_table(); if (class_table->UserVisibleNameFor(id()) == nullptr) { diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 8b110ac64ae..f901f03743d 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -2098,7 +2098,7 @@ class Class : public Object { const Field& field) const; #if !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER) - void SetUserVisibleNameInClassTable(); + void SetUserVisibleNameInClassTable() const; #endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER) private: diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc index afa595410fe..5d3d90eb720 100644 --- a/runtime/vm/service_test.cc +++ b/runtime/vm/service_test.cc @@ -454,11 +454,21 @@ ISOLATE_UNIT_TEST_CASE(Service_LocalVarDescriptors) { EXPECT(!class_a.IsNull()); const Function& function_c = Function::Handle(GetFunction(class_a, "c")); EXPECT(!function_c.IsNull()); - const Code& code_c = Code::Handle(function_c.CurrentCode()); - EXPECT(!code_c.IsNull()); - - const LocalVarDescriptors& descriptors = - LocalVarDescriptors::Handle(code_c.GetLocalVarDescriptors()); + LocalVarDescriptors& descriptors = LocalVarDescriptors::Handle(); + if (function_c.IsInterpreted()) { +#if defined(DART_DYNAMIC_MODULES) + const Bytecode& bytecode_c = Bytecode::Handle(function_c.GetBytecode()); + EXPECT(!bytecode_c.IsNull()); + descriptors = bytecode_c.var_descriptors(); +#else + UNREACHABLE(); +#endif + } else { + const Code& code_c = Code::Handle(function_c.CurrentCode()); + EXPECT(!code_c.IsNull()); + descriptors = code_c.GetLocalVarDescriptors(); + } + EXPECT(!descriptors.IsNull()); // Generate an ID for this object. ServiceIdZone& default_id_zone = isolate->EnsureDefaultServiceIdZone(); const char* id = default_id_zone.GetServiceId(descriptors);