[vm,dyn_modules] Fix/skip vm/cc tests that crash for dynamic modules.
Skip IR or snapshot-related tests when running from bytecode.
TEST=vm/cc/DartAPI_DeepStackTraceInfo
vm/cc/DartAPI_HeapSampling_UserDefinedClass
vm/cc/DartAPI_StackTraceInfo
vm/cc/DartAPI_StackOverflowStackTraceInfoArrowFunction
vm/cc/DartAPI_StackOverflowStackTraceInfoBraceFunction1
vm/cc/DartAPI_StackOverflowStackTraceInfoBraceFunction2
vm/cc/FrameLookup
vm/cc/Service_LocalVarDescriptors
Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try
Change-Id: I396a4e8ddacdbb88b3844e4113dc5c4ff6287e30
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/490083
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
This commit is contained in:
committed by
Commit Queue
parent
f92673c89a
commit
0bbb2ae821
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<const Function*> inlined_functions;
|
||||
GrowableArray<TokenPosition> token_positions;
|
||||
while (pc < end) {
|
||||
int instruction_length;
|
||||
Object* object;
|
||||
|
||||
+32
-26
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user