[kernel] Allow collection of token positions for unfinalized classes

E.g.
```
main() {
  new Foo();
}

class Foo {
  Foo() {
    print("hello from foo");
  }
}
```

debugging with --pause_isolates_on_start, the constructor (or anything else
in class Foo) would not be breakable from the Observatory interface.

This CL fixes that by collecting token positions from unfinalized classes.

Bug:
Change-Id: I93a20f3322b0a343a619625c71236b59c885cb7e
Reviewed-on: https://dart-review.googlesource.com/30441
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
This commit is contained in:
Jens Johansen 2017-12-20 11:59:47 +00:00 committed by commit-bot@chromium.org
parent 2eab494036
commit 45a59597fc
3 changed files with 73 additions and 30 deletions

View file

@ -9207,6 +9207,9 @@ void StreamingFlowGraphBuilder::CollectTokenPositionsFor(
} else if (tag == kField) {
FieldHelper field_helper(this);
field_helper.ReadUntilExcluding(FieldHelper::kEnd);
} else if (tag == kClass) {
ClassHelper class_helper(this);
class_helper.ReadUntilExcluding(ClassHelper::kEnd);
} else {
H.ReportError("Unsupported tag at this point: %d.", tag);
UNREACHABLE();

View file

@ -2676,35 +2676,53 @@ void CollectTokenPositionsFor(const Script& const_script) {
if (entry.IsClass()) {
const Class& klass = Class::Cast(entry);
entry_script = klass.script();
if (!entry_script.IsNull() && script.kernel_script_index() ==
entry_script.kernel_script_index()) {
if (!entry_script.IsNull() &&
(script.kernel_script_index() ==
entry_script.kernel_script_index()) &&
(script.kernel_string_offsets() ==
entry_script.kernel_string_offsets())) {
token_positions.Add(klass.token_pos().value());
}
Array& array = Array::Handle(zone_, klass.fields());
Field& field = Field::Handle(Z);
for (intptr_t i = 0; i < array.Length(); ++i) {
field ^= array.At(i);
if (field.kernel_offset() <= 0) {
// Skip artificially injected fields.
continue;
if (klass.is_finalized()) {
Array& array = Array::Handle(Z, klass.fields());
Field& field = Field::Handle(Z);
for (intptr_t i = 0; i < array.Length(); ++i) {
field ^= array.At(i);
if (field.kernel_offset() <= 0) {
// Skip artificially injected fields.
continue;
}
data = field.KernelData();
entry_script = field.Script();
ProcessTokenPositionsEntry(
data, script, entry_script, field.kernel_offset(),
field.KernelDataProgramOffset(), Z, &helper, &token_positions,
&yield_positions);
}
data = field.KernelData();
entry_script = field.Script();
ProcessTokenPositionsEntry(
data, script, entry_script, field.kernel_offset(),
field.KernelDataProgramOffset(), zone_, &helper, &token_positions,
&yield_positions);
}
array = klass.functions();
Function& function = Function::Handle(Z);
for (intptr_t i = 0; i < array.Length(); ++i) {
function ^= array.At(i);
data = function.KernelData();
entry_script = function.script();
ProcessTokenPositionsEntry(
data, script, entry_script, function.kernel_offset(),
function.KernelDataProgramOffset(), zone_, &helper,
&token_positions, &yield_positions);
array = klass.functions();
Function& function = Function::Handle(Z);
for (intptr_t i = 0; i < array.Length(); ++i) {
function ^= array.At(i);
data = function.KernelData();
entry_script = function.script();
ProcessTokenPositionsEntry(
data, script, entry_script, function.kernel_offset(),
function.KernelDataProgramOffset(), Z, &helper,
&token_positions, &yield_positions);
}
} else {
// Class isn't finalized yet: read the data attached to it.
ASSERT(klass.kernel_offset() > 0);
data = lib.kernel_data();
ASSERT(!data.IsNull());
const intptr_t library_kernel_offset = lib.kernel_offset();
ASSERT(library_kernel_offset > 0);
const intptr_t class_offset = klass.kernel_offset();
entry_script = klass.script();
ProcessTokenPositionsEntry(data, script, entry_script, class_offset,
library_kernel_offset, Z, &helper,
&token_positions, &yield_positions);
}
} else if (entry.IsFunction()) {
const Function& function = Function::Cast(entry);
@ -2712,7 +2730,7 @@ void CollectTokenPositionsFor(const Script& const_script) {
entry_script = function.script();
ProcessTokenPositionsEntry(data, script, entry_script,
function.kernel_offset(),
function.KernelDataProgramOffset(), zone_,
function.KernelDataProgramOffset(), Z,
&helper, &token_positions, &yield_positions);
} else if (entry.IsField()) {
const Field& field = Field::Cast(entry);
@ -2724,8 +2742,8 @@ void CollectTokenPositionsFor(const Script& const_script) {
entry_script = field.Script();
ProcessTokenPositionsEntry(data, script, entry_script,
field.kernel_offset(),
field.KernelDataProgramOffset(), zone_,
&helper, &token_positions, &yield_positions);
field.KernelDataProgramOffset(), Z, &helper,
&token_positions, &yield_positions);
}
}
}

View file

@ -3565,16 +3565,37 @@ void Class::set_token_pos(TokenPosition token_pos) const {
}
TokenPosition Class::ComputeEndTokenPos() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return TokenPosition::kNoSource;
#else
// Return the begin token for synthetic classes.
if (is_synthesized_class() || IsMixinApplication() || IsTopLevel()) {
return token_pos();
}
Zone* zone = Thread::Current()->zone();
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Script& scr = Script::Handle(zone, script());
ASSERT(!scr.IsNull());
if (scr.kind() == RawScript::kKernelTag) {
ASSERT(kernel_offset() > 0);
const Library& lib = Library::Handle(zone, library());
const TypedData& kernel_data = TypedData::Handle(zone, lib.kernel_data());
ASSERT(!kernel_data.IsNull());
const intptr_t library_kernel_offset = lib.kernel_offset();
ASSERT(library_kernel_offset > 0);
const intptr_t class_offset = kernel_offset();
kernel::TranslationHelper helper(thread);
helper.InitFromScript(scr);
kernel::StreamingFlowGraphBuilder builder_(&helper, scr, zone, kernel_data,
0);
builder_.SetOffset(class_offset);
kernel::ClassHelper class_helper(&builder_);
class_helper.ReadUntilIncluding(kernel::ClassHelper::kEndPosition);
if (class_helper.end_position_.IsReal()) return class_helper.end_position_;
TokenPosition largest_seen = token_pos();
// Walk through all functions and get their end_tokens to find the classes
@ -3613,6 +3634,7 @@ TokenPosition Class::ComputeEndTokenPos() const {
}
UNREACHABLE();
return TokenPosition::kNoSource;
#endif
}
int32_t Class::SourceFingerprint() const {