[vm/debugger] Support debugging of interpreted frames.

Change-Id: Iaf59e6ed887ed973fcfc7f1c414ad52ef98f01d7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100270
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Régis Crelier
2019-05-31 21:40:32 +00:00
committed by commit-bot@chromium.org
parent 0e07987ccd
commit cddf2bbdfe
21 changed files with 1102 additions and 546 deletions
-63
View File
@@ -1,63 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Script for generating bytecode in a kernel file using Dart 2 pipeline and
# interpreting the resulting bytecode.
# Usage
# pkg/vm/tool/test_bytecode ~/foo.dart
set -e
# Pick the architecture and mode to test.
BUILD_FLAGS="-m release -a x64"
BUILD_SUBDIR="ReleaseX64"
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
CUR_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$CUR_DIR/../../.."
BUILD_DIR="$SDK_DIR/out/$BUILD_SUBDIR"
# Regenerate vm_platform_strong.dill to contain bytecode if needed:
# $SDK_DIR/tools/gn.py $BUILD_FLAGS --bytecode
# $SDK_DIR/tools/build.py $BUILD_FLAGS runtime
# Generate dill file containing bytecode for input dart source.
$CUR_DIR/gen_kernel --platform $BUILD_DIR/vm_platform_strong.dill \
--gen-bytecode $@ -o $BUILD_DIR/test_bytecode.dill
# Dump bytecode in generated vm_platform_strong.dill file to platform.txt.
# $BUILD_DIR/dart $SDK_DIR/pkg/vm/bin/dump_kernel.dart \
# $BUILD_DIR/vm_platform_strong.dill $BUILD_DIR/platform.txt
# Dump bytecode in generated test_bytecode.dill file to test_bytecode.txt.
# $BUILD_DIR/dart $SDK_DIR/pkg/vm/bin/dump_kernel.dart \
# $BUILD_DIR/test_bytecode.dill $BUILD_DIR/test_bytecode.txt
# Required flag.
DART_VM_FLAGS="--enable-interpreter $DART_VM_FLAGS"
# Optional flags examples. Uncomment as needed.
# DART_VM_FLAGS="--compilation-counter-threshold=-1 $DART_VM_FLAGS"
# DART_VM_FLAGS="--force-log-flush --isolate-log-filter=\"\" $DART_VM_FLAGS"
# DART_VM_FLAGS="--dump-kernel-bytecode $DART_VM_FLAGS"
# DART_VM_FLAGS="--trace-interpreter-after=0 $DART_VM_FLAGS"
# Execute dill file.
exec $BUILD_DIR/dart $DART_VM_FLAGS $BUILD_DIR/test_bytecode.dill
@@ -8,6 +8,7 @@
#include "vm/compiler/assembler/disassembler_kbc.h"
#include "platform/assert.h"
#include "vm/compiler/frontend/bytecode_reader.h"
#include "vm/constants_kbc.h"
#include "vm/cpu.h"
#include "vm/instructions.h"
@@ -408,6 +409,22 @@ void KernelBytecodeDisassembler::Disassemble(const Function& function) {
PcDescriptors::Handle(zone, bytecode.pc_descriptors());
THR_Print("%s}\n", descriptors.ToCString());
if (bytecode.HasSourcePositions()) {
THR_Print("Source positions for function '%s' {\n", function_fullname);
// 4 bits per hex digit + 2 for "0x".
const int addr_width = (kBitsPerWord / 4) + 2;
// "*" in a printf format specifier tells it to read the field width from
// the printf argument list.
THR_Print("%-*s\ttok-ix\n", addr_width, "pc");
kernel::BytecodeSourcePositionsIterator iter(zone, bytecode);
while (iter.MoveNext()) {
THR_Print("%#-*" Px "\t%s\n", addr_width,
bytecode.PayloadStart() + iter.PcOffset(),
iter.TokenPos().ToCString());
}
THR_Print("}\n");
}
THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
const ExceptionHandlers& handlers =
ExceptionHandlers::Handle(zone, bytecode.exception_handlers());
@@ -1951,7 +1951,7 @@ FlowGraph* BytecodeFlowGraphBuilder::BuildGraph() {
}
while (update_position &&
pc_ >= source_pos_iter.BytecodeInstructionIndex()) {
static_cast<uword>(pc_) >= source_pos_iter.PcOffset()) {
position_ = source_pos_iter.TokenPos();
update_position = source_pos_iter.MoveNext();
}
@@ -12,6 +12,7 @@
#include "vm/compiler/frontend/bytecode_scope_builder.h"
#include "vm/constants_kbc.h"
#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/longjump.h"
#include "vm/object_store.h"
#include "vm/reusable_handles.h"
@@ -2231,6 +2232,10 @@ RawError* BytecodeReader::ReadFunctionBytecode(Thread* thread,
bytecode_metadata_helper.ReadMetadata(function);
#if !defined(PRODUCT)
thread->isolate()->debugger()->NotifyBytecodeLoaded(function);
#endif
return Error::null();
} else {
return thread->StealStickyError();
@@ -309,12 +309,7 @@ class BytecodeSourcePositionsIterator : ValueObject {
return true;
}
intptr_t BytecodeInstructionIndex() const { return cur_bci_; }
uword PcOffset() const {
return KernelBytecode::BytecodePcToOffset(BytecodeInstructionIndex(),
/* is_return_address = */ true);
}
uword PcOffset() const { return cur_bci_; }
TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
+1 -3
View File
@@ -258,9 +258,7 @@ DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
bool Compiler::CanOptimizeFunction(Thread* thread, const Function& function) {
#if !defined(PRODUCT)
Isolate* isolate = thread->isolate();
if (isolate->debugger()->IsStepping() ||
isolate->debugger()->HasBreakpoint(function, thread->zone())) {
if (Debugger::IsDebugging(thread, function)) {
// We cannot set breakpoints and single step in optimized code,
// so do not optimize the function. Bump usage counter down to avoid
// repeatedly entering the runtime for an optimization attempt.
+3 -10
View File
@@ -971,20 +971,12 @@ class KernelBytecode {
}
}
DART_FORCE_INLINE static bool IsCallOpcode(const KBCInstr* instr) {
DART_FORCE_INLINE static bool IsCallOpcode_Old(const KBCInstr* instr) {
switch (DecodeOpcode(instr)) {
case KernelBytecode::kDirectCall_Old:
case KernelBytecode::kInterfaceCall_Old:
case KernelBytecode::kUncheckedInterfaceCall_Old:
case KernelBytecode::kDynamicCall_Old:
case KernelBytecode::kDirectCall:
case KernelBytecode::kDirectCall_Wide:
case KernelBytecode::kInterfaceCall:
case KernelBytecode::kInterfaceCall_Wide:
case KernelBytecode::kUncheckedInterfaceCall:
case KernelBytecode::kUncheckedInterfaceCall_Wide:
case KernelBytecode::kDynamicCall:
case KernelBytecode::kDynamicCall_Wide:
return true;
default:
@@ -1014,7 +1006,7 @@ class KernelBytecode {
// to new _GrowableList<E>(0).
return kNativeCallToGrowableListArgc;
}
ASSERT(IsCallOpcode(call));
ASSERT(IsCallOpcode_Old(call));
return DecodeA(call);
}
@@ -1030,6 +1022,7 @@ class KernelBytecode {
// Converts bytecode PC into an offset.
// For return addresses used in PcDescriptors, PC is also augmented by 1.
// TODO(regis): Eliminate this correction.
static intptr_t BytecodePcToOffset(uint32_t pc, bool is_return_address) {
return pc + (is_return_address ? 1 : 0);
}
+775 -347
View File
File diff suppressed because it is too large Load Diff
+75 -23
View File
@@ -7,6 +7,7 @@
#include "include/dart_tools_api.h"
#include "vm/constants_kbc.h"
#include "vm/kernel_isolate.h"
#include "vm/object.h"
#include "vm/port.h"
@@ -140,12 +141,7 @@ class BreakpointLocation {
intptr_t requested_line_number() const { return requested_line_number_; }
intptr_t requested_column_number() const { return requested_column_number_; }
intptr_t LineNumber();
intptr_t ColumnNumber();
void GetCodeLocation(Library* lib,
Script* script,
TokenPosition* token_pos) const;
void GetCodeLocation(Script* script, TokenPosition* token_pos) const;
Breakpoint* AddRepeated(Debugger* dbg);
Breakpoint* AddSingleShot(Debugger* dbg);
@@ -154,13 +150,21 @@ class BreakpointLocation {
bool for_over_await);
bool AnyEnabled() const;
bool IsResolved() const { return is_resolved_; }
bool IsResolved() const {
return bytecode_token_pos_.IsReal() || code_token_pos_.IsReal();
}
bool IsResolved(bool in_bytecode) const {
return in_bytecode ? bytecode_token_pos_.IsReal()
: code_token_pos_.IsReal();
}
bool IsLatent() const { return !token_pos_.IsReal(); }
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
void SetResolved(const Function& func, TokenPosition token_pos);
void SetResolved(bool in_bytecode,
const Function& func,
TokenPosition token_pos);
BreakpointLocation* next() const { return this->next_; }
void set_next(BreakpointLocation* value) { next_ = value; }
@@ -174,7 +178,6 @@ class BreakpointLocation {
RawString* url_;
TokenPosition token_pos_;
TokenPosition end_token_pos_;
bool is_resolved_;
BreakpointLocation* next_;
Breakpoint* conditions_;
intptr_t requested_line_number_;
@@ -182,22 +185,23 @@ class BreakpointLocation {
// Valid for resolved breakpoints:
RawFunction* function_;
intptr_t line_number_;
intptr_t column_number_;
TokenPosition bytecode_token_pos_;
TokenPosition code_token_pos_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(BreakpointLocation);
};
// CodeBreakpoint represents a location in compiled code. There may be
// more than one CodeBreakpoint for one BreakpointLocation, e.g. when a
// function gets compiled as a regular function and as a closure.
// CodeBreakpoint represents a location in compiled or interpreted code.
// There may be more than one CodeBreakpoint for one BreakpointLocation,
// e.g. when a function gets compiled as a regular function and as a closure.
class CodeBreakpoint {
public:
CodeBreakpoint(const Code& code,
TokenPosition token_pos,
uword pc,
RawPcDescriptors::Kind kind);
CodeBreakpoint(const Bytecode& bytecode, TokenPosition token_pos, uword pc);
~CodeBreakpoint();
RawFunction* function() const;
@@ -211,6 +215,7 @@ class CodeBreakpoint {
void Enable();
void Disable();
bool IsEnabled() const { return is_enabled_; }
bool IsInterpreted() const { return bytecode_ != Bytecode::null(); }
RawCode* OrigStubAddress() const;
@@ -225,8 +230,11 @@ class CodeBreakpoint {
void PatchCode();
void RestoreCode();
void SetBytecodeBreak();
void UnsetBytecodeBreak();
RawCode* code_;
RawBytecode* bytecode_;
TokenPosition token_pos_;
uword pc_;
intptr_t line_number_;
@@ -271,6 +279,16 @@ class ActivationFrame : public ZoneAllocated {
ActivationFrame(uword pc, const Code& code);
#if !defined(DART_PRECOMPILED_RUNTIME)
ActivationFrame(uword pc,
uword fp,
uword sp,
const Bytecode& bytecode,
Kind kind = kRegular);
ActivationFrame(uword pc, const Bytecode& bytecode);
#endif // !defined(DART_PRECOMPILED_RUNTIME)
explicit ActivationFrame(Kind kind);
explicit ActivationFrame(const Closure& async_activation);
@@ -286,7 +304,11 @@ class ActivationFrame : public ZoneAllocated {
ASSERT(!code_.IsNull());
return code_;
}
bool is_interpreted() const { return is_interpreted_; }
const Bytecode& bytecode() const {
ASSERT(!bytecode_.IsNull());
return bytecode_;
}
bool IsInterpreted() const { return !bytecode_.IsNull(); }
RawString* QualifiedFunctionName();
RawString* SourceUrl();
@@ -398,6 +420,7 @@ class ActivationFrame : public ZoneAllocated {
// The anchor of the context chain for this function.
Context& ctx_;
Code& code_;
Bytecode& bytecode_;
Function& function_;
bool live_frame_; // Is this frame a live frame?
bool token_pos_initialized_;
@@ -415,7 +438,6 @@ class ActivationFrame : public ZoneAllocated {
Kind kind_;
bool is_interpreted_; // Running under kernel bytecode interpreter.
bool vars_initialized_;
LocalVarDescriptors& var_descriptors_;
ZoneGrowableArray<intptr_t> desc_indices_;
@@ -441,6 +463,7 @@ class DebuggerStackTrace : public ZoneAllocated {
void AddActivation(ActivationFrame* frame);
void AddMarker(ActivationFrame::Kind marker);
void AddAsyncCausalFrame(uword pc, const Code& code);
void AddAsyncCausalFrame(uword pc, const Bytecode& bytecode);
ZoneGrowableArray<ActivationFrame*> trace_;
@@ -475,7 +498,12 @@ class Debugger {
void OnIsolateRunnable();
void NotifyCompilation(const Function& func);
void NotifyCompilation(const Function& func) {
HandleCodeChange(/* bytecode_loaded = */ false, func);
}
void NotifyBytecodeLoaded(const Function& func) {
HandleCodeChange(/* bytecode_loaded = */ true, func);
}
void NotifyDoneLoading();
RawFunction* ResolveFunction(const Library& library,
@@ -546,6 +574,7 @@ class Debugger {
// debugger's zone.
bool HasBreakpoint(const Function& func, Zone* zone);
bool HasBreakpoint(const Code& code);
// A Bytecode version of HasBreakpoint is not needed.
// Returns true if the call at address pc is patched to point to
// a debugger stub.
@@ -597,6 +626,7 @@ class Debugger {
void PrintSettingsToJSONObject(JSONObject* jsobj) const;
static bool IsDebuggable(const Function& func);
static bool IsDebugging(Thread* thread, const Function& func);
intptr_t limitBreakpointId() { return next_id_; }
@@ -625,19 +655,30 @@ class Debugger {
void FindCompiledFunctions(const Script& script,
TokenPosition start_pos,
TokenPosition end_pos,
GrowableObjectArray* function_list);
GrowableObjectArray* bytecode_function_list,
GrowableObjectArray* code_function_list);
bool FindBestFit(const Script& script,
TokenPosition token_pos,
TokenPosition last_token_pos,
Function* best_fit);
RawFunction* FindInnermostClosure(const Function& function,
TokenPosition token_pos);
TokenPosition ResolveBreakpointPos(const Function& func,
TokenPosition ResolveBreakpointPos(bool in_bytecode,
const Function& func,
TokenPosition requested_token_pos,
TokenPosition last_token_pos,
intptr_t requested_column,
TokenPosition exact_token_pos);
void DeoptimizeWorld();
BreakpointLocation* SetCodeBreakpoints(bool in_bytecode,
BreakpointLocation* loc,
const Script& script,
TokenPosition token_pos,
TokenPosition last_token_pos,
intptr_t requested_line,
intptr_t requested_column,
TokenPosition exact_token_pos,
const GrowableObjectArray& functions);
BreakpointLocation* SetBreakpoint(const Script& script,
TokenPosition token_pos,
TokenPosition last_token_pos,
@@ -653,10 +694,13 @@ class Debugger {
intptr_t column);
void RegisterBreakpointLocation(BreakpointLocation* bpt);
void RegisterCodeBreakpoint(CodeBreakpoint* bpt);
BreakpointLocation* GetBreakpointLocation(const Script& script,
TokenPosition token_pos,
intptr_t requested_column,
bool is_resolved = false);
BreakpointLocation* GetBreakpointLocation(
const Script& script,
TokenPosition token_pos,
intptr_t requested_line,
intptr_t requested_column,
TokenPosition bytecode_token_pos = TokenPosition::kNoSource,
TokenPosition code_token_pos = TokenPosition::kNoSource);
void MakeCodeBreakpointAt(const Function& func, BreakpointLocation* bpt);
// Returns NULL if no breakpoint exists for the given address.
CodeBreakpoint* GetCodeBreakpoint(uword breakpoint_address);
@@ -665,6 +709,8 @@ class Debugger {
void PrintBreakpointsListToJSONArray(BreakpointLocation* sbpt,
JSONArray* jsarr) const;
void HandleCodeChange(bool bytecode_loaded, const Function& func);
ActivationFrame* TopDartFrame() const;
static ActivationFrame* CollectDartFrame(
Isolate* isolate,
@@ -675,6 +721,12 @@ class Debugger {
intptr_t deopt_frame_offset,
ActivationFrame::Kind kind = ActivationFrame::kRegular);
#if !defined(DART_PRECOMPILED_RUNTIME)
static ActivationFrame* CollectDartFrame(
Isolate* isolate,
uword pc,
StackFrame* frame,
const Bytecode& bytecode,
ActivationFrame::Kind kind = ActivationFrame::kRegular);
static RawArray* DeoptimizeToArray(Thread* thread,
StackFrame* frame,
const Code& code);
+33
View File
@@ -0,0 +1,33 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/debugger.h"
#include "vm/instructions_kbc.h"
namespace dart {
#ifndef PRODUCT
void CodeBreakpoint::SetBytecodeBreak() {
ASSERT(!is_enabled_);
ASSERT(!Isolate::Current()->is_using_old_bytecode_instructions());
// TODO(regis): Register pc_ (or the token pos range including pc_) with the
// interpreter as a debug break address.
is_enabled_ = true;
}
void CodeBreakpoint::UnsetBytecodeBreak() {
ASSERT(is_enabled_);
// TODO(regis): Unregister pc_ (or the token pos range including pc_) with the
// interpreter as a debug break address.
is_enabled_ = false;
}
#endif // !PRODUCT
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)
+1 -1
View File
@@ -896,7 +896,7 @@ DART_FORCE_INLINE bool Interpreter::InstanceCall2(Thread* thread,
} while (0)
#endif
// Fetch next operation from PC, increment program counter and dispatch.
// Fetch next operation from PC and dispatch.
#define DISPATCH() DISPATCH_OP(*pc)
// Load target of a jump instruction into PC.
+2 -4
View File
@@ -524,10 +524,9 @@ void JSONObject::AddLocation(const BreakpointLocation* bpt_loc) const {
ASSERT(bpt_loc->IsResolved());
Zone* zone = Thread::Current()->zone();
Library& library = Library::Handle(zone);
Script& script = Script::Handle(zone);
TokenPosition token_pos = TokenPosition::kNoSource;
bpt_loc->GetCodeLocation(&library, &script, &token_pos);
bpt_loc->GetCodeLocation(&script, &token_pos);
AddLocation(script, token_pos);
}
@@ -536,10 +535,9 @@ void JSONObject::AddUnresolvedLocation(
ASSERT(!bpt_loc->IsResolved());
Zone* zone = Thread::Current()->zone();
Library& library = Library::Handle(zone);
Script& script = Script::Handle(zone);
TokenPosition token_pos = TokenPosition::kNoSource;
bpt_loc->GetCodeLocation(&library, &script, &token_pos);
bpt_loc->GetCodeLocation(&script, &token_pos);
JSONObject location(this, "location");
location.AddProperty("type", "UnresolvedSourceLocation");
+94 -34
View File
@@ -256,7 +256,7 @@ static RawArray* AsSortedDuplicateFreeArray(GrowableArray<intptr_t>* source) {
return array_object.raw();
}
static void ProcessTokenPositionsEntry(
static void CollectKernelDataTokenPositions(
const TypedDataBase& kernel_data,
const Script& script,
const Script& entry_script,
@@ -278,6 +278,64 @@ static void ProcessTokenPositionsEntry(
token_position_collector.CollectTokenPositions(kernel_offset);
}
static void CollectBytecodeTokenPositions(
const Bytecode& bytecode,
Zone* zone,
GrowableArray<intptr_t>* token_positions,
GrowableArray<intptr_t>* yield_positions) {
ASSERT(bytecode.HasSourcePositions());
BytecodeSourcePositionsIterator iter(zone, bytecode);
while (iter.MoveNext()) {
const TokenPosition pos = iter.TokenPos();
if (pos.IsReal()) {
// TODO(alexmarkov): collect yield positions from bytecode.
token_positions->Add(pos.value());
}
}
}
static void CollectBytecodeFunctionTokenPositions(
const Function& function,
GrowableArray<intptr_t>* token_positions,
GrowableArray<intptr_t>* yield_positions) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
ASSERT(function.is_declared_in_bytecode());
if (!function.HasBytecode()) {
const Object& result = Object::Handle(
zone, BytecodeReader::ReadFunctionBytecode(thread, function));
if (!result.IsNull()) {
Exceptions::PropagateError(Error::Cast(result));
}
}
Bytecode& bytecode = Bytecode::Handle(zone, function.bytecode());
ASSERT(!bytecode.IsNull());
if (bytecode.HasSourcePositions()) {
CollectBytecodeTokenPositions(bytecode, zone, token_positions,
yield_positions);
// Find closure functions in the object pool.
const ObjectPool& pool = ObjectPool::Handle(zone, bytecode.object_pool());
Object& object = Object::Handle(zone);
Function& closure = Function::Handle(zone);
for (intptr_t i = 0; i < pool.Length(); i++) {
ObjectPool::EntryType entry_type = pool.TypeAt(i);
if (entry_type != ObjectPool::EntryType::kTaggedObject) {
continue;
}
object = pool.ObjectAt(i);
if (object.IsFunction()) {
closure ^= object.raw();
if ((closure.kind() == RawFunction::kClosureFunction) &&
(closure.raw() != function.raw())) {
bytecode = closure.bytecode();
CollectBytecodeTokenPositions(bytecode, zone, token_positions,
yield_positions);
}
}
}
}
}
void CollectTokenPositionsFor(const Script& interesting_script) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
@@ -325,29 +383,30 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
continue;
}
data = temp_field.KernelData();
ProcessTokenPositionsEntry(data, interesting_script, entry_script,
temp_field.kernel_offset(),
temp_field.KernelDataProgramOffset(),
zone, &helper, &token_positions,
&yield_positions);
CollectKernelDataTokenPositions(
data, interesting_script, entry_script,
temp_field.kernel_offset(),
temp_field.KernelDataProgramOffset(), zone, &helper,
&token_positions, &yield_positions);
}
temp_array = klass.functions();
for (intptr_t i = 0; i < temp_array.Length(); ++i) {
temp_function ^= temp_array.At(i);
entry_script = temp_function.script();
// TODO(alexmarkov): collect token positions from bytecode
if (temp_function.is_declared_in_bytecode()) {
continue;
}
if (entry_script.raw() != interesting_script.raw()) {
continue;
}
data = temp_function.KernelData();
ProcessTokenPositionsEntry(data, interesting_script, entry_script,
temp_function.kernel_offset(),
temp_function.KernelDataProgramOffset(),
zone, &helper, &token_positions,
&yield_positions);
if (temp_function.is_declared_in_bytecode()) {
CollectBytecodeFunctionTokenPositions(
temp_function, &token_positions, &yield_positions);
} else {
data = temp_function.KernelData();
CollectKernelDataTokenPositions(
data, interesting_script, entry_script,
temp_function.kernel_offset(),
temp_function.KernelDataProgramOffset(), zone, &helper,
&token_positions, &yield_positions);
}
}
} else {
// Class isn't finalized yet: read the data attached to it.
@@ -362,27 +421,28 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
if (entry_script.raw() != interesting_script.raw()) {
continue;
}
ProcessTokenPositionsEntry(data, interesting_script, entry_script,
class_offset, library_kernel_offset, zone,
&helper, &token_positions,
&yield_positions);
CollectKernelDataTokenPositions(data, interesting_script,
entry_script, class_offset,
library_kernel_offset, zone, &helper,
&token_positions, &yield_positions);
}
} else if (entry.IsFunction()) {
temp_function ^= entry.raw();
// TODO(alexmarkov): collect token positions from bytecode
if (temp_function.is_declared_in_bytecode()) {
continue;
}
entry_script = temp_function.script();
if (entry_script.raw() != interesting_script.raw()) {
continue;
}
data = temp_function.KernelData();
ProcessTokenPositionsEntry(data, interesting_script, entry_script,
temp_function.kernel_offset(),
temp_function.KernelDataProgramOffset(),
zone, &helper, &token_positions,
&yield_positions);
if (temp_function.is_declared_in_bytecode()) {
CollectBytecodeFunctionTokenPositions(temp_function, &token_positions,
&yield_positions);
} else {
data = temp_function.KernelData();
CollectKernelDataTokenPositions(
data, interesting_script, entry_script,
temp_function.kernel_offset(),
temp_function.KernelDataProgramOffset(), zone, &helper,
&token_positions, &yield_positions);
}
} else if (entry.IsField()) {
const Field& field = Field::Cast(entry);
// TODO(alexmarkov): collect token positions from bytecode
@@ -395,10 +455,10 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
continue;
}
data = field.KernelData();
ProcessTokenPositionsEntry(data, interesting_script, entry_script,
field.kernel_offset(),
field.KernelDataProgramOffset(), zone,
&helper, &token_positions, &yield_positions);
CollectKernelDataTokenPositions(
data, interesting_script, entry_script, field.kernel_offset(),
field.KernelDataProgramOffset(), zone, &helper, &token_positions,
&yield_positions);
}
}
}
+33 -3
View File
@@ -5727,9 +5727,10 @@ void Function::AttachBytecode(const Bytecode& value) const {
StorePointer(&raw_ptr()->bytecode_, value.raw());
// We should not have loaded the bytecode if the function had code.
ASSERT(!HasCode());
if (FLAG_enable_interpreter) {
// However, we may load the bytecode to access source positions (see
// ProcessBytecodeTokenPositionsEntry in kernel.cc).
// In that case, do not install InterpretCall stub below.
if (FLAG_enable_interpreter && !HasCode()) {
// Set the code entry_point to InterpretCall stub.
SetInstructions(StubCode::InterpretCall());
}
@@ -15235,6 +15236,35 @@ TokenPosition Bytecode::GetTokenIndexOfPC(uword pc) const {
#endif
}
intptr_t Bytecode::GetTryIndexAtPc(uword return_address) const {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
intptr_t try_index = -1;
const uword pc_offset = return_address - PayloadStart();
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
while (iter.MoveNext()) {
// PC descriptors for try blocks in bytecode are generated in pairs,
// marking start and end of a try block.
// See BytecodeMetadataHelper::ReadExceptionsTable for details.
const intptr_t current_try_index = iter.TryIndex();
const uword start_pc = iter.PcOffset();
if (pc_offset < start_pc) {
break;
}
const bool has_next = iter.MoveNext();
ASSERT(has_next);
const uword end_pc = iter.PcOffset();
if (start_pc <= pc_offset && pc_offset < end_pc) {
ASSERT(try_index < current_try_index);
try_index = current_try_index;
}
}
return try_index;
#endif
}
const char* Bytecode::ToCString() const {
return Thread::Current()->zone()->PrintToString("Bytecode(%s)",
QualifiedName());
+3
View File
@@ -2182,6 +2182,8 @@ class Function : public Object {
void AttachBytecode(const Bytecode& bytecode) const;
RawBytecode* bytecode() const { return raw_ptr()->bytecode_; }
inline bool HasBytecode() const;
#else
inline bool HasBytecode() const { return false; }
#endif
virtual intptr_t Hash() const;
@@ -5501,6 +5503,7 @@ class Bytecode : public Object {
RawTypedDataBase* GetBinary(Zone* zone) const;
TokenPosition GetTokenIndexOfPC(uword pc) const;
intptr_t GetTryIndexAtPc(uword return_address) const;
intptr_t instructions_binary_offset() const {
return raw_ptr()->instructions_binary_offset_;
+1 -1
View File
@@ -537,7 +537,7 @@ bool RawBytecode::ContainsPC(RawObject* raw_obj, uword pc) {
RawBytecode* raw_bytecode = static_cast<RawBytecode*>(raw_obj);
uword start = raw_bytecode->ptr()->instructions_;
uword size = raw_bytecode->ptr()->instructions_size_;
return (pc - start) < size;
return (pc - start) <= size; // pc may point past last instruction.
}
return false;
}
+1
View File
@@ -1349,6 +1349,7 @@ class RawBytecode : public RawObject {
VISIT_FROM(RawObject*, object_pool_);
RawObjectPool* object_pool_;
RawFunction* function_;
RawArray* closures_;
RawExceptionHandlers* exception_handlers_;
RawPcDescriptors* pc_descriptors_;
NOT_IN_PRODUCT(RawLocalVarDescriptors* var_descriptors_);
+10 -3
View File
@@ -976,6 +976,7 @@ DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
ASSERT(!caller_frame->is_interpreted());
const Code& orig_stub = Code::Handle(
zone, isolate->debugger()->GetPatchedStubAddress(caller_frame->pc()));
const Error& error =
@@ -1964,13 +1965,13 @@ static void HandleStackOverflowTestCases(Thread* thread) {
for (intptr_t i = 0; i < num_frames; i++) {
ActivationFrame* frame = stack->FrameAt(i);
#ifndef DART_PRECOMPILED_RUNTIME
if (!frame->is_interpreted()) {
if (!frame->IsInterpreted()) {
// Ensure that we have unoptimized code.
frame->function().EnsureHasCompiledUnoptimizedCode();
}
// TODO(regis): Provide var descriptors in kernel bytecode.
const int num_vars =
frame->is_interpreted() ? 0 : frame->NumLocalVariables();
frame->IsInterpreted() ? 0 : frame->NumLocalVariables();
#else
// Variable locations and number are unknown when precompiling.
const int num_vars = 0;
@@ -2130,8 +2131,14 @@ DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) {
ASSERT(FLAG_enable_interpreter || optimizing_compilation);
ASSERT((!optimizing_compilation) || function.HasCode());
if ((!optimizing_compilation) ||
#if defined(PRODUCT)
if (!optimizing_compilation ||
Compiler::CanOptimizeFunction(thread, function)) {
#else
if ((!optimizing_compilation && !Debugger::IsDebugging(thread, function)) ||
(optimizing_compilation &&
Compiler::CanOptimizeFunction(thread, function))) {
#endif // defined(PRODUCT)
if (FLAG_background_compilation) {
if (FLAG_enable_inlining_annotations) {
FATAL("Cannot enable inlining annotations and background compilation");
+39 -22
View File
@@ -191,6 +191,10 @@ bool SourceReport::ScriptIsLoadedByLibrary(const Script& script,
void SourceReport::PrintCallSitesData(JSONObject* jsobj,
const Function& function,
const Code& code) {
if (code.IsNull()) {
// TODO(regis): implement for bytecode.
return;
}
const TokenPosition begin_pos = function.token_pos();
const TokenPosition end_pos = function.end_token_pos();
@@ -230,6 +234,10 @@ void SourceReport::PrintCallSitesData(JSONObject* jsobj,
void SourceReport::PrintCoverageData(JSONObject* jsobj,
const Function& function,
const Code& code) {
if (code.IsNull()) {
// TODO(regis): implement for bytecode.
return;
}
const TokenPosition begin_pos = function.token_pos();
const TokenPosition end_pos = function.end_token_pos();
@@ -312,15 +320,8 @@ void SourceReport::PrintCoverageData(JSONObject* jsobj,
void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj,
const Function& func,
const Code& code) {
const uint8_t kSafepointKind =
(RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall |
RawPcDescriptors::kRuntimeCall);
const TokenPosition begin_pos = func.token_pos();
const TokenPosition end_pos = func.end_token_pos();
const PcDescriptors& descriptors =
PcDescriptors::Handle(zone(), code.pc_descriptors());
intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1;
GrowableArray<char> possible(func_length);
possible.SetLength(func_length);
@@ -328,15 +329,37 @@ void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj,
possible[i] = false;
}
PcDescriptors::Iterator iter(descriptors, kSafepointKind);
while (iter.MoveNext()) {
const TokenPosition token_pos = iter.TokenPos();
if ((token_pos < begin_pos) || (token_pos > end_pos)) {
// Does not correspond to a valid source position.
continue;
if (code.IsNull()) {
const Bytecode& bytecode = Bytecode::Handle(func.bytecode());
ASSERT(!bytecode.IsNull());
kernel::BytecodeSourcePositionsIterator iter(zone(), bytecode);
while (iter.MoveNext()) {
const TokenPosition token_pos = iter.TokenPos();
if ((token_pos < begin_pos) || (token_pos > end_pos)) {
// Does not correspond to a valid source position.
continue;
}
intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
possible[token_offset] = true;
}
} else {
const uint8_t kSafepointKind =
(RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall |
RawPcDescriptors::kRuntimeCall);
const PcDescriptors& descriptors =
PcDescriptors::Handle(zone(), code.pc_descriptors());
PcDescriptors::Iterator iter(descriptors, kSafepointKind);
while (iter.MoveNext()) {
const TokenPosition token_pos = iter.TokenPos();
if ((token_pos < begin_pos) || (token_pos > end_pos)) {
// Does not correspond to a valid source position.
continue;
}
intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
possible[token_offset] = true;
}
intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
possible[token_offset] = true;
}
JSONArray bpts(jsobj, "possibleBreakpoints");
@@ -465,14 +488,8 @@ void SourceReport::VisitFunction(JSONArray* jsarr, const Function& func) {
range.AddProperty("scriptIndex", GetScriptIndex(script));
range.AddProperty("startPos", begin_pos);
range.AddProperty("endPos", end_pos);
// TODO(regis): What is the meaning of 'compiled' in the presence of bytecode?
// If it means 'called', it should say 'true' if bytecode is present.
range.AddProperty("compiled", !code.IsNull());
range.AddProperty("compiled", true); // bytecode or code.
// TODO(regis): Do we want a report covering interpreted functions too?
if (code.IsNull()) {
return;
}
if (IsReportRequested(kCallSites)) {
PrintCallSitesData(&range, func, code);
}
+6 -25
View File
@@ -180,11 +180,9 @@ const char* StackFrame::ToCString() const {
if (is_interpreted()) {
const Bytecode& bytecode = Bytecode::Handle(zone, LookupDartBytecode());
ASSERT(!bytecode.IsNull());
const Function& function = Function::Handle(zone, bytecode.function());
ASSERT(!function.IsNull());
return zone->PrintToString(
"[%-8s : sp(%#" Px ") fp(%#" Px ") pc(%#" Px ") bytecode %s ]",
GetName(), sp(), fp(), pc(), function.ToFullyQualifiedCString());
return zone->PrintToString("[%-8s : sp(%#" Px ") fp(%#" Px ") pc(%#" Px
") %s ]",
GetName(), sp(), fp(), pc(), bytecode.Name());
}
const Code& code = Code::Handle(zone, LookupDartCode());
ASSERT(!code.IsNull());
@@ -501,7 +499,6 @@ bool StackFrame::FindExceptionHandler(Thread* thread,
ASSERT(!bytecode.IsNull());
start = bytecode.PayloadStart();
handlers = bytecode.exception_handlers();
descriptors = bytecode.pc_descriptors();
} else {
code = LookupDartCode();
if (code.IsNull()) {
@@ -520,33 +517,17 @@ bool StackFrame::FindExceptionHandler(Thread* thread,
*has_catch_all = info->has_catch_all;
return true;
}
uword pc_offset = pc() - start;
if (handlers.num_entries() == 0) {
return false;
}
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
intptr_t try_index = -1;
if (is_interpreted()) {
while (iter.MoveNext()) {
// PC descriptors for try blocks in bytecode are generated in pairs,
// marking start and end of a try block.
// See BytecodeMetadataHelper::ReadExceptionsTable for details.
const intptr_t current_try_index = iter.TryIndex();
const uword start_pc = iter.PcOffset();
if (pc_offset < start_pc) {
break;
}
const bool has_next = iter.MoveNext();
ASSERT(has_next);
const uword end_pc = iter.PcOffset();
if (start_pc <= pc_offset && pc_offset < end_pc) {
ASSERT(try_index < current_try_index);
try_index = current_try_index;
}
}
try_index = bytecode.GetTryIndexAtPc(pc());
} else {
uword pc_offset = pc() - code.PayloadStart();
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
while (iter.MoveNext()) {
const intptr_t current_try_index = iter.TryIndex();
if ((iter.PcOffset() == pc_offset) && (current_try_index != -1)) {
+1
View File
@@ -85,6 +85,7 @@ vm_sources = [
"debugger_arm64.cc",
"debugger_dbc.cc",
"debugger_ia32.cc",
"debugger_kbc.cc",
"debugger_x64.cc",
"deferred_objects.cc",
"deferred_objects.h",