mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[vm/debugger] Adds pragma support for func. decl.
This fixes issue #45710 by adding support for pragma annotations on local functions which are lazily created via the flow graph builder (as opposed to the kernel loader). TEST=Added regression test to notify_debugger_on_exception_test.dart Bug: https://github.com/dart-lang/sdk/issues/45710, https://github.com/dart-lang/sdk/issues/45987 Change-Id: I13f2f8d2b7d05ea1cb423c142537789e99a919d3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/199420 Commit-Queue: Clement Skau <cskau@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
1989b7f376
commit
6523c58119
|
@ -9,7 +9,12 @@
|
|||
import 'test_helper.dart';
|
||||
import 'service_test_common.dart';
|
||||
|
||||
const int LINE_A = 24;
|
||||
const int LINE_A = 16;
|
||||
const int LINE_B = 32;
|
||||
|
||||
syncThrow() {
|
||||
throw 'Hello from syncThrow!'; // Line A.
|
||||
}
|
||||
|
||||
@pragma('vm:notify-debugger-on-exception')
|
||||
void catchNotifyDebugger(Function() code) {
|
||||
|
@ -20,17 +25,30 @@ void catchNotifyDebugger(Function() code) {
|
|||
}
|
||||
}
|
||||
|
||||
syncThrow() {
|
||||
throw 'Hello from syncThrow!'; // Line A.
|
||||
void catchNotifyDebuggerNested() {
|
||||
@pragma('vm:notify-debugger-on-exception')
|
||||
void nested() {
|
||||
try {
|
||||
throw 'Hello from nested!'; // Line B.
|
||||
} catch (e) {
|
||||
// Ignore. Internals will notify debugger.
|
||||
}
|
||||
}
|
||||
|
||||
nested();
|
||||
}
|
||||
|
||||
testMain() {
|
||||
catchNotifyDebugger(syncThrow);
|
||||
catchNotifyDebuggerNested();
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedWithUnhandledException,
|
||||
stoppedAtLine(LINE_A),
|
||||
resumeIsolate,
|
||||
hasStoppedWithUnhandledException,
|
||||
stoppedAtLine(LINE_B),
|
||||
];
|
||||
|
||||
main([args = const <String>[]]) => runIsolateTests(args, tests,
|
||||
|
|
|
@ -9,7 +9,12 @@
|
|||
import 'test_helper.dart';
|
||||
import 'service_test_common.dart';
|
||||
|
||||
const int LINE_A = 24;
|
||||
const int LINE_A = 16;
|
||||
const int LINE_B = 32;
|
||||
|
||||
syncThrow() {
|
||||
throw 'Hello from syncThrow!'; // Line A.
|
||||
}
|
||||
|
||||
@pragma('vm:notify-debugger-on-exception')
|
||||
void catchNotifyDebugger(Function() code) {
|
||||
|
@ -20,17 +25,30 @@ void catchNotifyDebugger(Function() code) {
|
|||
}
|
||||
}
|
||||
|
||||
syncThrow() {
|
||||
throw 'Hello from syncThrow!'; // Line A.
|
||||
void catchNotifyDebuggerNested() {
|
||||
@pragma('vm:notify-debugger-on-exception')
|
||||
void nested() {
|
||||
try {
|
||||
throw 'Hello from nested!'; // Line B.
|
||||
} catch (e) {
|
||||
// Ignore. Internals will notify debugger.
|
||||
}
|
||||
}
|
||||
|
||||
nested();
|
||||
}
|
||||
|
||||
testMain() {
|
||||
catchNotifyDebugger(syncThrow);
|
||||
catchNotifyDebuggerNested();
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedWithUnhandledException,
|
||||
stoppedAtLine(LINE_A),
|
||||
resumeIsolate,
|
||||
hasStoppedWithUnhandledException,
|
||||
stoppedAtLine(LINE_B),
|
||||
];
|
||||
|
||||
main([args = const <String>[]]) => runIsolateTests(args, tests,
|
||||
|
|
|
@ -1257,6 +1257,7 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
|
|||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::BuildStatement() {
|
||||
intptr_t offset = ReaderOffset();
|
||||
Tag tag = ReadTag(); // read tag.
|
||||
switch (tag) {
|
||||
case kExpressionStatement:
|
||||
|
@ -1300,7 +1301,7 @@ Fragment StreamingFlowGraphBuilder::BuildStatement() {
|
|||
case kVariableDeclaration:
|
||||
return BuildVariableDeclaration();
|
||||
case kFunctionDeclaration:
|
||||
return BuildFunctionDeclaration();
|
||||
return BuildFunctionDeclaration(offset);
|
||||
default:
|
||||
ReportUnexpectedTag("statement", tag);
|
||||
UNREACHABLE();
|
||||
|
@ -4241,7 +4242,9 @@ Fragment StreamingFlowGraphBuilder::BuildMapLiteral(TokenPosition* p) {
|
|||
|
||||
Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() {
|
||||
ReadPosition(); // read position.
|
||||
return BuildFunctionNode(TokenPosition::kNoSource, StringIndex());
|
||||
return BuildFunctionNode(TokenPosition::kNoSource, StringIndex(),
|
||||
/*has_valid_annotation=*/false, /*has_pragma=*/false,
|
||||
/*func_decl_offset=*/0);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* p) {
|
||||
|
@ -5424,16 +5427,39 @@ Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration() {
|
|||
return instructions;
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration() {
|
||||
TokenPosition position = ReadPosition(); // read position.
|
||||
intptr_t variable_offset = ReaderOffset() + data_program_offset_;
|
||||
Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration(intptr_t offset) {
|
||||
TokenPosition position = ReadPosition();
|
||||
const intptr_t variable_offset = ReaderOffset() + data_program_offset_;
|
||||
|
||||
// read variable declaration.
|
||||
// Read variable declaration.
|
||||
VariableDeclarationHelper helper(this);
|
||||
|
||||
bool has_pragma = false;
|
||||
bool has_valid_annotation = false;
|
||||
helper.ReadUntilExcluding(VariableDeclarationHelper::kAnnotations);
|
||||
const intptr_t annotation_count = ReadListLength();
|
||||
for (intptr_t i = 0; i < annotation_count; ++i) {
|
||||
const intptr_t tag = PeekTag();
|
||||
if (tag != kInvalidExpression) {
|
||||
has_valid_annotation = true;
|
||||
}
|
||||
if (tag == kConstantExpression) {
|
||||
auto& instance = Instance::Handle();
|
||||
instance = constant_reader_.ReadConstantExpression();
|
||||
if (instance.clazz() == IG->object_store()->pragma_class()) {
|
||||
has_pragma = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
SkipExpression();
|
||||
}
|
||||
helper.SetJustRead(VariableDeclarationHelper::kAnnotations);
|
||||
|
||||
helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);
|
||||
|
||||
Fragment instructions = DebugStepCheck(position);
|
||||
instructions += BuildFunctionNode(position, helper.name_index_);
|
||||
instructions += BuildFunctionNode(position, helper.name_index_,
|
||||
has_valid_annotation, has_pragma, offset);
|
||||
instructions += StoreLocal(position, LookupVariable(variable_offset));
|
||||
instructions += Drop();
|
||||
return instructions;
|
||||
|
@ -5441,7 +5467,10 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration() {
|
|||
|
||||
Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
|
||||
TokenPosition parent_position,
|
||||
StringIndex name_index) {
|
||||
StringIndex name_index,
|
||||
bool has_valid_annotation,
|
||||
bool has_pragma,
|
||||
intptr_t func_decl_offset) {
|
||||
intptr_t offset = ReaderOffset();
|
||||
|
||||
FunctionNodeHelper function_node_helper(this);
|
||||
|
@ -5500,6 +5529,13 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
|
|||
*name, parsed_function()->function(), position);
|
||||
}
|
||||
|
||||
function.set_has_pragma(has_pragma);
|
||||
if ((FLAG_enable_mirrors && has_valid_annotation) || has_pragma) {
|
||||
auto& lib =
|
||||
Library::Handle(Z, Class::Handle(Z, function.Owner()).library());
|
||||
lib.AddMetadata(function, func_decl_offset);
|
||||
}
|
||||
|
||||
function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
|
||||
FunctionNodeHelper::kSync);
|
||||
switch (function_node_helper.dart_async_marker_) {
|
||||
|
|
|
@ -350,9 +350,12 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
|
|||
Fragment BuildTryFinally();
|
||||
Fragment BuildYieldStatement();
|
||||
Fragment BuildVariableDeclaration();
|
||||
Fragment BuildFunctionDeclaration();
|
||||
Fragment BuildFunctionDeclaration(intptr_t offset);
|
||||
Fragment BuildFunctionNode(TokenPosition parent_position,
|
||||
StringIndex name_index);
|
||||
StringIndex name_index,
|
||||
bool has_valid_annotation,
|
||||
bool has_pragma,
|
||||
intptr_t func_decl_offset);
|
||||
|
||||
// Build flow graph for '_nativeEffect'.
|
||||
Fragment BuildNativeEffect();
|
||||
|
|
|
@ -452,8 +452,16 @@ class MetadataEvaluator : public KernelReaderHelper {
|
|||
} else if (tag == kConstructor) {
|
||||
ConstructorHelper constructor_helper(this);
|
||||
constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations);
|
||||
} else if (tag == kFunctionDeclaration) {
|
||||
ReadTag();
|
||||
ReadPosition(); // fileOffset
|
||||
VariableDeclarationHelper variable_declaration_helper(this);
|
||||
variable_declaration_helper.ReadUntilExcluding(
|
||||
VariableDeclarationHelper::kAnnotations);
|
||||
} else {
|
||||
FATAL("No support for metadata on this type of kernel node\n");
|
||||
FATAL("No support for metadata on this type of kernel node: %" Pd32
|
||||
"\n",
|
||||
tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue