[vm] Account for bytecode in profile processing and Observatory.
Change-Id: I220eca1f4a3aadaa271ead4de698c28e4a7b653a
Reviewed-on: https://dart-review.googlesource.com/c/84447
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 1ed1327..04a3e89 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -86,6 +86,18 @@
return NULL;
}
+const uint8_t* VmServiceIONativeSymbol(Dart_NativeFunction nf) {
+ intptr_t n =
+ sizeof(_VmServiceIONativeEntries) / sizeof(_VmServiceIONativeEntries[0]);
+ for (intptr_t i = 0; i < n; i++) {
+ VmServiceIONativeEntry entry = _VmServiceIONativeEntries[i];
+ if (reinterpret_cast<Dart_NativeFunction>(entry.function) == nf) {
+ return reinterpret_cast<const uint8_t*>(entry.name);
+ }
+ }
+ return NULL;
+}
+
const char* VmService::error_msg_ = NULL;
char VmService::server_uri_[kServerUriStringBufferSize];
@@ -93,7 +105,8 @@
Dart_Handle url = DartUtils::NewString(kVMServiceIOLibraryUri);
Dart_Handle library = Dart_LookupLibrary(url);
if (!Dart_IsError(library)) {
- Dart_SetNativeResolver(library, VmServiceIONativeResolver, NULL);
+ Dart_SetNativeResolver(library, VmServiceIONativeResolver,
+ VmServiceIONativeSymbol);
}
}
@@ -120,7 +133,8 @@
SHUTDOWN_ON_ERROR(library);
result = Dart_SetRootLibrary(library);
SHUTDOWN_ON_ERROR(library);
- result = Dart_SetNativeResolver(library, VmServiceIONativeResolver, NULL);
+ result = Dart_SetNativeResolver(library, VmServiceIONativeResolver,
+ VmServiceIONativeSymbol);
SHUTDOWN_ON_ERROR(result);
// Make runnable.
diff --git a/runtime/observatory/lib/src/elements/function_view.dart b/runtime/observatory/lib/src/elements/function_view.dart
index 57d775a..3c32189 100644
--- a/runtime/observatory/lib/src/elements/function_view.dart
+++ b/runtime/observatory/lib/src/elements/function_view.dart
@@ -288,6 +288,21 @@
]
]);
}
+ if (_function.bytecode != null) {
+ members.add(new DivElement()
+ ..classes = ['memberItem']
+ ..children = <Element>[
+ new DivElement()
+ ..classes = ['memberName']
+ ..text = 'bytecode',
+ new DivElement()
+ ..classes = ['memberName']
+ ..children = <Element>[
+ new CodeRefElement(_isolate, _function.bytecode,
+ queue: _r.queue),
+ ]
+ ]);
+ }
members.add(new DivElement()
..classes = ['memberItem']
..text = ' ');
diff --git a/runtime/observatory/lib/src/models/objects/function.dart b/runtime/observatory/lib/src/models/objects/function.dart
index e619f5e..541dcad 100644
--- a/runtime/observatory/lib/src/models/objects/function.dart
+++ b/runtime/observatory/lib/src/models/objects/function.dart
@@ -87,6 +87,9 @@
CodeRef get unoptimizedCode;
/// [optional]
+ CodeRef get bytecode;
+
+ /// [optional]
FieldRef get field;
int get usageCounter;
InstanceRef get icDataArray;
diff --git a/runtime/observatory/lib/src/repositories/heap_snapshot.dart b/runtime/observatory/lib/src/repositories/heap_snapshot.dart
index cea60e2..198af19 100644
--- a/runtime/observatory/lib/src/repositories/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/repositories/heap_snapshot.dart
@@ -90,12 +90,13 @@
}
void reuse() {
- _onProgress =
+ final onProgress =
new StreamController<HeapSnapshotLoadingProgressEvent>.broadcast();
- (() async {
- _triggerOnProgress();
- _onProgress.close();
- }());
+ Timer.run(() {
+ onProgress.add(new HeapSnapshotLoadingProgressEvent(this));
+ onProgress.close();
+ });
+ _onProgress = onProgress;
}
}
diff --git a/runtime/observatory/lib/src/repositories/sample_profile.dart b/runtime/observatory/lib/src/repositories/sample_profile.dart
index 3dace5a..27d03c5 100644
--- a/runtime/observatory/lib/src/repositories/sample_profile.dart
+++ b/runtime/observatory/lib/src/repositories/sample_profile.dart
@@ -115,12 +115,13 @@
}
void reuse() {
- _onProgress =
+ final onProgress =
new StreamController<SampleProfileLoadingProgressEvent>.broadcast();
- (() async {
- _triggerOnProgress();
- _onProgress.close();
- }());
+ Timer.run(() {
+ onProgress.add(new SampleProfileLoadingProgressEvent(this));
+ onProgress.close();
+ });
+ _onProgress = onProgress;
}
}
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index f296309..7ebc69c 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -3135,6 +3135,7 @@
SourceLocation location;
Code code;
Code unoptimizedCode;
+ Code bytecode;
bool isOptimizable;
bool isInlinable;
bool hasIntrinsic;
@@ -3193,6 +3194,7 @@
isInlinable = map['_inlinable'];
isRecognized = map['_recognized'];
unoptimizedCode = map['_unoptimizedCode'];
+ bytecode = map['_bytecode'];
deoptimizations = map['_deoptimizations'];
usageCounter = map['_usageCounter'];
icDataArray = map['_icDataArray'];
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/function.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/function.dart
index bbe2c28..00f3ca5 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/objects/function.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/function.dart
@@ -33,6 +33,7 @@
final M.SourceLocation location;
final M.CodeRef code;
final M.CodeRef unoptimizedCode;
+ final M.CodeRef bytecode;
final M.FieldRef field;
final int usageCounter;
final M.InstanceRef icDataArray;
@@ -55,6 +56,7 @@
this.location,
this.code,
this.unoptimizedCode,
+ this.bytecode,
this.field,
this.usageCounter: 0,
this.icDataArray: const InstanceRefMock(),
diff --git a/runtime/observatory/tests/service/get_object_rpc_test.dart b/runtime/observatory/tests/service/get_object_rpc_test.dart
index 15ed8df..3f0ff6c 100644
--- a/runtime/observatory/tests/service/get_object_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_object_rpc_test.dart
@@ -952,8 +952,8 @@
};
var result = await isolate.invokeRpcNoUpgrade('getObject', params);
expect(result['type'], equals('Code'));
- expect(result['name'], equals('_DummyClass.dummyFunction'));
- expect(result['_vmName'], equals('dummyFunction'));
+ expect(result['name'], endsWith('_DummyClass.dummyFunction'));
+ expect(result['_vmName'], endsWith('dummyFunction'));
expect(result['kind'], equals('Dart'));
expect(result['_optimized'], new isInstanceOf<bool>());
expect(result['function']['type'], equals('@Function'));
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 50b3846..f4edb7f 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -708,10 +708,9 @@
{
InterpreterSetjmpBuffer buffer(this);
if (!setjmp(buffer.buffer_)) {
- thread->set_vm_tag(reinterpret_cast<uword>(entrypoint));
result = entrypoint(code, argdesc_, call_base, thread);
- thread->set_vm_tag(VMTag::kDartInterpretedTagId);
thread->set_top_exit_frame_info(0);
+ ASSERT(thread->vm_tag() == VMTag::kDartInterpretedTagId);
ASSERT(thread->execution_state() == Thread::kThreadInGenerated);
} else {
return false;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 4d20ed2..cd878c1 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -15103,7 +15103,7 @@
// Regular stub.
const char* name = StubCode::NameOfStub(EntryPoint());
if (name == NULL) {
- return zone->PrintToString("[this stub]"); // Not yet recorded.
+ return zone->PrintToString("[unknown stub]"); // Not yet recorded.
}
return zone->PrintToString("[Stub] %s", name);
} else if (obj.IsClass()) {
@@ -15114,10 +15114,10 @@
} else {
ASSERT(obj.IsFunction());
// Dart function.
- const char* opt = is_optimized() ? "*" : "";
+ const char* opt = is_optimized() ? "[Optimized]" : "[Unoptimized]";
const char* function_name =
String::Handle(zone, Function::Cast(obj).UserVisibleName()).ToCString();
- return zone->PrintToString("%s%s", opt, function_name);
+ return zone->PrintToString("%s %s", opt, function_name);
}
}
@@ -15125,11 +15125,11 @@
Zone* zone = Thread::Current()->zone();
const Object& obj = Object::Handle(zone, owner());
if (obj.IsFunction()) {
- const char* opt = is_optimized() ? "*" : "";
+ const char* opt = is_optimized() ? "[Optimized]" : "[Unoptimized]";
const char* function_name =
String::Handle(zone, Function::Cast(obj).QualifiedScrubbedName())
.ToCString();
- return zone->PrintToString("%s%s", opt, function_name);
+ return zone->PrintToString("%s %s", opt, function_name);
}
return Name();
}
@@ -15304,12 +15304,6 @@
return instr.LengthInBytes();
}
-bool Bytecode::ContainsInstructionAt(uword addr) const {
- const ExternalTypedData& instr = ExternalTypedData::Handle(instructions());
- const uword offset = addr - reinterpret_cast<uword>(instr.DataAddr(0));
- return offset < static_cast<uword>(instr.LengthInBytes());
-}
-
void Bytecode::Disassemble(DisassemblyFormatter* formatter) const {
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -15389,7 +15383,7 @@
ASSERT(!fun.IsNull());
const char* function_name =
String::Handle(zone, fun.UserVisibleName()).ToCString();
- return zone->PrintToString("%s", function_name);
+ return zone->PrintToString("[Bytecode] %s", function_name);
}
const char* Bytecode::QualifiedName() const {
@@ -15398,7 +15392,23 @@
ASSERT(!fun.IsNull());
const char* function_name =
String::Handle(zone, fun.QualifiedScrubbedName()).ToCString();
- return zone->PrintToString("%s", function_name);
+ return zone->PrintToString("[Bytecode] %s", function_name);
+}
+
+bool Bytecode::SlowFindRawBytecodeVisitor::FindObject(
+ RawObject* raw_obj) const {
+ return RawBytecode::ContainsPC(raw_obj, pc_);
+}
+
+RawBytecode* Bytecode::FindCode(uword pc) {
+ Thread* thread = Thread::Current();
+ HeapIterationScope heap_iteration_scope(thread);
+ SlowFindRawBytecodeVisitor visitor(pc);
+ RawObject* needle = thread->heap()->FindOldObject(&visitor);
+ if (needle != Bytecode::null()) {
+ return static_cast<RawBytecode*>(needle);
+ }
+ return Bytecode::null();
}
RawContext* Context::New(intptr_t num_variables, Heap::Space space) {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 5ac93eb..cfa12c8 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -5302,7 +5302,10 @@
intptr_t Size() const;
RawObjectPool* object_pool() const { return raw_ptr()->object_pool_; }
- bool ContainsInstructionAt(uword addr) const;
+
+ bool ContainsInstructionAt(uword addr) const {
+ return RawBytecode::ContainsPC(raw(), addr);
+ }
RawPcDescriptors* pc_descriptors() const {
return raw_ptr()->pc_descriptors_;
@@ -5358,6 +5361,22 @@
const char* Name() const;
const char* QualifiedName() const;
+ class SlowFindRawBytecodeVisitor : public FindObjectVisitor {
+ public:
+ explicit SlowFindRawBytecodeVisitor(uword pc) : pc_(pc) {}
+ virtual ~SlowFindRawBytecodeVisitor() {}
+
+ // Check if object matches find condition.
+ virtual bool FindObject(RawObject* obj) const;
+
+ private:
+ const uword pc_;
+
+ DISALLOW_COPY_AND_ASSIGN(SlowFindRawBytecodeVisitor);
+ };
+
+ static RawBytecode* FindCode(uword pc);
+
private:
void set_object_pool(const ObjectPool& object_pool) const {
StorePointer(&raw_ptr()->object_pool_, object_pool.raw());
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 964dc6d..3080fe7 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -315,7 +315,7 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
Bytecode& bytecode = Bytecode::Handle(this->bytecode());
if (!bytecode.IsNull()) {
- jsobj.AddProperty("bytecode", bytecode);
+ jsobj.AddProperty("_bytecode", bytecode);
}
#endif // !DART_PRECOMPILED_RUNTIME
Array& ics = Array::Handle(ic_data_array());
@@ -794,6 +794,8 @@
}
void Code::PrintJSONImpl(JSONStream* stream, bool ref) const {
+ // N.B. This is polymorphic with Bytecode.
+
JSONObject jsobj(stream);
AddCommonObjectProperties(&jsobj, "Code", ref);
jsobj.AddFixedServiceId("code/%" Px64 "-%" Px "", compile_timestamp(),
@@ -860,11 +862,21 @@
}
void Bytecode::PrintJSONImpl(JSONStream* stream, bool ref) const {
+ // N.B. This is polymorphic with Code.
+
JSONObject jsobj(stream);
- AddCommonObjectProperties(&jsobj, "Bytecode", ref);
+ AddCommonObjectProperties(&jsobj, "Code", ref);
+ int64_t compile_timestamp = 0;
+ jsobj.AddFixedServiceId("code/%" Px64 "-%" Px "", compile_timestamp,
+ PayloadStart());
const char* qualified_name = QualifiedName();
const char* vm_name = Name();
AddNameProperties(&jsobj, qualified_name, vm_name);
+
+ jsobj.AddProperty("kind", "Dart");
+ jsobj.AddProperty("_optimized", false);
+ jsobj.AddProperty("_intrinsic", false);
+ jsobj.AddProperty("_native", false);
if (ref) {
return;
}
@@ -872,6 +884,7 @@
jsobj.AddProperty("function", fun);
jsobj.AddPropertyF("_startAddress", "%" Px "", PayloadStart());
jsobj.AddPropertyF("_endAddress", "%" Px "", PayloadStart() + Size());
+ jsobj.AddProperty("_alive", true);
const ObjectPool& obj_pool = ObjectPool::Handle(object_pool());
jsobj.AddProperty("_objectPool", obj_pool);
{
@@ -884,6 +897,9 @@
JSONObject desc(&jsobj, "_descriptors");
descriptors.PrintToJSONObject(&desc, false);
}
+
+ { JSONArray inlined_functions(&jsobj, "_inlinedFunctions"); }
+ { JSONArray inline_intervals(&jsobj, "_inlinedIntervals"); }
}
void Context::PrintJSONImpl(JSONStream* stream, bool ref) const {
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index f5b9a86..fbb891a 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -1409,9 +1409,7 @@
&counters_);
}
-CodeDescriptor::CodeDescriptor(const Code& code) : code_(code) {
- ASSERT(!code_.IsNull());
-}
+CodeDescriptor::CodeDescriptor(const AbstractCode code) : code_(code) {}
uword CodeDescriptor::Start() const {
return code_.PayloadStart();
@@ -1438,15 +1436,10 @@
~CodeLookupTableBuilder() {}
void VisitObject(RawObject* raw_obj) {
- uint32_t tags = raw_obj->ptr()->tags_;
- if (RawObject::ClassIdTag::decode(tags) == kCodeCid) {
- RawCode* raw_code = reinterpret_cast<RawCode*>(raw_obj);
- const Code& code = Code::Handle(raw_code);
- ASSERT(!code.IsNull());
- const Instructions& instructions =
- Instructions::Handle(code.instructions());
- ASSERT(!instructions.IsNull());
- table_->Add(code);
+ if (raw_obj->IsCode()) {
+ table_->Add(Code::Handle(Code::RawCast(raw_obj)));
+ } else if (raw_obj->IsBytecode()) {
+ table_->Add(Bytecode::Handle(Bytecode::RawCast(raw_obj)));
}
}
@@ -1495,9 +1488,10 @@
#endif
}
-void CodeLookupTable::Add(const Code& code) {
+void CodeLookupTable::Add(const Object& code) {
ASSERT(!code.IsNull());
- CodeDescriptor* cd = new CodeDescriptor(code);
+ ASSERT(code.IsCode() || code.IsBytecode());
+ CodeDescriptor* cd = new CodeDescriptor(AbstractCode(code.raw()));
code_objects_.Add(cd);
}
@@ -1672,7 +1666,12 @@
uword pc_marker,
uword* stack_buffer) {
ASSERT(cd != NULL);
- const Code& code = Code::Handle(cd->code());
+ if (cd->code().IsBytecode()) {
+ // Bytecode frame build is atomic from the profiler's perspective: no
+ // missing frame.
+ return;
+ }
+ const Code& code = Code::Handle(Code::RawCast(cd->code().raw()));
ASSERT(!code.IsNull());
// Some stubs (and intrinsics) do not push a frame onto the stack leaving
// the frame pointer in the caller.
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index 951abed..c6f868d 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -434,10 +434,83 @@
}
};
+class AbstractCode {
+ public:
+ explicit AbstractCode(RawObject* code) : code_(Object::Handle(code)) {
+ ASSERT(code_.IsNull() || code_.IsCode() || code_.IsBytecode());
+ }
+
+ RawObject* raw() const { return code_.raw(); }
+ const Object* handle() const { return &code_; }
+
+ uword PayloadStart() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).PayloadStart();
+ } else {
+ return Bytecode::Cast(code_).PayloadStart();
+ }
+ }
+
+ uword Size() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).Size();
+ } else {
+ return Bytecode::Cast(code_).Size();
+ }
+ }
+
+ int64_t compile_timestamp() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).compile_timestamp();
+ } else {
+ return 0;
+ }
+ }
+
+ const char* Name() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).Name();
+ } else {
+ return Bytecode::Cast(code_).Name();
+ }
+ }
+
+ const char* QualifiedName() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).QualifiedName();
+ } else {
+ return Bytecode::Cast(code_).QualifiedName();
+ }
+ }
+
+ RawObject* owner() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).owner();
+ } else {
+ return Bytecode::Cast(code_).function();
+ }
+ }
+
+ bool IsNull() const { return code_.IsNull(); }
+ bool IsCode() const { return code_.IsCode(); }
+ bool IsBytecode() const { return code_.IsBytecode(); }
+
+ bool is_optimized() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).is_optimized();
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ const Object& code_;
+};
+
// A Code object descriptor.
class CodeDescriptor : public ZoneAllocated {
public:
- explicit CodeDescriptor(const Code& code);
+ explicit CodeDescriptor(const AbstractCode code);
uword Start() const;
@@ -445,7 +518,7 @@
int64_t CompileTimestamp() const;
- RawCode* code() const { return code_.raw(); }
+ const AbstractCode code() const { return code_; }
const char* Name() const { return code_.Name(); }
@@ -471,7 +544,7 @@
}
private:
- const Code& code_;
+ const AbstractCode code_;
DISALLOW_COPY_AND_ASSIGN(CodeDescriptor);
};
@@ -492,7 +565,7 @@
private:
void Build(Thread* thread);
- void Add(const Code& code);
+ void Add(const Object& code);
// Code objects sorted by entry.
ZoneGrowableArray<CodeDescriptor*> code_objects_;
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index a67a883..b2405f8 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -272,7 +272,7 @@
uword start,
uword end,
int64_t timestamp,
- const Code& code)
+ const AbstractCode code)
: kind_(kind),
start_(start),
end_(end),
@@ -482,7 +482,7 @@
obj.AddProperty("exclusiveTicks", exclusive_ticks());
if (kind() == kDartCode) {
ASSERT(!code_.IsNull());
- obj.AddProperty("code", code_);
+ obj.AddProperty("code", *code_.handle());
} else if (kind() == kCollectedCode) {
PrintCollectedCode(&obj);
} else if (kind() == kReusedCode) {
@@ -1196,7 +1196,7 @@
extra_tags_(extra_tags),
profile_(profile),
deoptimized_code_(new DeoptimizedCodeSet(thread->isolate())),
- null_code_(Code::ZoneHandle()),
+ null_code_(Code::null()),
null_function_(Function::ZoneHandle()),
tick_functions_(false),
inclusive_tree_(false),
@@ -1288,8 +1288,7 @@
for (intptr_t i = 0; i < code_lookup_table.length(); i++) {
const CodeDescriptor* descriptor = code_lookup_table.At(i);
ASSERT(descriptor != NULL);
- const Code& code = Code::Handle(descriptor->code());
- ASSERT(!code.IsNull());
+ const AbstractCode code = descriptor->code();
RegisterLiveProfileCode(new ProfileCode(
ProfileCode::kDartCode, code.PayloadStart(),
code.PayloadStart() + code.Size(), code.compile_timestamp(), code));
@@ -1426,7 +1425,6 @@
}
// Walk the sampled PCs.
- Code& code = Code::Handle();
for (intptr_t frame_index = sample->length() - 1; frame_index >= 0;
frame_index--) {
ASSERT(sample->At(frame_index) != 0);
@@ -1436,7 +1434,7 @@
ProfileCode* profile_code =
GetProfileCode(sample->At(frame_index), sample->timestamp());
ASSERT(profile_code->code_table_index() == index);
- code ^= profile_code->code();
+ const AbstractCode code = profile_code->code();
current = AppendKind(code, current, sample);
current = current->GetChild(index);
current->Tick(sample, (frame_index == 0));
@@ -1469,7 +1467,6 @@
}
// Walk the sampled PCs.
- Code& code = Code::Handle();
for (intptr_t frame_index = 0; frame_index < sample->length();
frame_index++) {
ASSERT(sample->At(frame_index) != 0);
@@ -1479,7 +1476,7 @@
ProfileCode* profile_code =
GetProfileCode(sample->At(frame_index), sample->timestamp());
ASSERT(profile_code->code_table_index() == index);
- code ^= profile_code->code();
+ const AbstractCode code = profile_code->code();
current = current->GetChild(index);
if (ShouldTickNode(sample, frame_index)) {
current->Tick(sample, (frame_index == 0));
@@ -1592,7 +1589,12 @@
ASSERT(function != NULL);
const intptr_t code_index = profile_code->code_table_index();
ASSERT(profile_code != NULL);
- const Code& code = Code::ZoneHandle(profile_code->code());
+ Code& code = Code::ZoneHandle();
+ if (profile_code->code().IsCode()) {
+ code ^= profile_code->code().raw();
+ } else {
+ // No inlining in bytecode.
+ }
GrowableArray<const Function*>* inlined_functions = NULL;
GrowableArray<TokenPosition>* inlined_token_positions = NULL;
TokenPosition token_position = TokenPosition::kNoSource;
@@ -1846,7 +1848,7 @@
return current;
}
- ProfileCodeTrieNode* AppendKind(const Code& code,
+ ProfileCodeTrieNode* AppendKind(const AbstractCode code,
ProfileCodeTrieNode* current,
ProcessedSample* sample) {
if (code.IsNull()) {
@@ -2200,7 +2202,6 @@
}
// We haven't seen this pc yet.
- Code& code = Code::Handle(thread_->zone());
// Check NativeSymbolResolver for pc.
uintptr_t native_start = 0;
@@ -2237,7 +2238,7 @@
ASSERT(pc >= native_start);
profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start,
- pc + 1, 0, code);
+ pc + 1, 0, null_code_);
if (native_name != NULL) {
profile_code->SetName(native_name);
NativeSymbolResolver::FreeSymbolName(native_name);
@@ -2301,7 +2302,7 @@
intptr_t extra_tags_;
Profile* profile_;
DeoptimizedCodeSet* deoptimized_code_;
- const Code& null_code_;
+ const AbstractCode null_code_;
const Function& null_function_;
bool tick_functions_;
bool inclusive_tree_;
diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h
index ba1981a..6e7d660 100644
--- a/runtime/vm/profiler_service.h
+++ b/runtime/vm/profiler_service.h
@@ -10,6 +10,7 @@
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/object.h"
+#include "vm/profiler.h"
#include "vm/tags.h"
#include "vm/thread_interrupter.h"
#include "vm/token_position.h"
@@ -158,7 +159,7 @@
uword start,
uword end,
int64_t timestamp,
- const Code& code);
+ const AbstractCode code);
Kind kind() const { return kind_; }
@@ -195,7 +196,7 @@
void IncInclusiveTicks() { inclusive_ticks_++; }
bool IsOptimizedDart() const;
- RawCode* code() const { return code_.raw(); }
+ const AbstractCode code() const { return code_; }
const char* name() const { return name_; }
void SetName(const char* name);
@@ -228,7 +229,7 @@
intptr_t inclusive_ticks_;
intptr_t inclusive_serial_;
- const Code& code_;
+ const AbstractCode code_;
char* name_;
int64_t compile_timestamp_;
ProfileFunction* function_;
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 9f4b0f6..1cb8236 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -282,18 +282,18 @@
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT(!walker.Down());
// Inclusive code: main -> B.boo.
walker.Reset(Profile::kInclusiveCode);
// Move down from the root.
EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
@@ -618,18 +618,18 @@
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT(!walker.Down());
// Inclusive code: main -> B.boo.
walker.Reset(Profile::kInclusiveCode);
// Move down from the root.
EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
@@ -747,11 +747,11 @@
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
@@ -761,12 +761,12 @@
walker.Reset(Profile::kInclusiveCode);
// Move down from the root.
EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
@@ -923,11 +923,11 @@
EXPECT(walker.Down());
EXPECT_STREQ("Double_add", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("_Double._add", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] _Double._add", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("_Double.+", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] _Double.+", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -990,9 +990,9 @@
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] AllocateArray", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("new _List", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] new _List", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -1080,7 +1080,7 @@
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] AllocateContext", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -1212,9 +1212,9 @@
EXPECT(walker.Down());
EXPECT_STREQ("TypedData_Float32Array_new", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("new Float32List", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] new Float32List", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -1294,10 +1294,10 @@
EXPECT_STREQ("String_concat", walker.CurrentName());
EXPECT(walker.Down());
#if 1
- EXPECT_STREQ("_StringBase.+", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] _StringBase.+", walker.CurrentName());
EXPECT(walker.Down());
#endif
- EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -1376,13 +1376,16 @@
EXPECT(walker.Down());
EXPECT_STREQ("OneByteString_allocate", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("_OneByteString._allocate", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] _OneByteString._allocate",
+ walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("_OneByteString._concatAll", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] _OneByteString._concatAll",
+ walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("_StringBase._interpolate", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] _StringBase._interpolate",
+ walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("foo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -1493,12 +1496,12 @@
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
- EXPECT_STREQ("*B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
@@ -1507,13 +1510,13 @@
// We have two code objects: mainA and B.boo.
walker.Reset(Profile::kInclusiveCode);
EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
- EXPECT_STREQ("*B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
@@ -1613,11 +1616,11 @@
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("*B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(!walker.Down());
@@ -1626,11 +1629,11 @@
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("*B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
@@ -1889,45 +1892,45 @@
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("orange", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] orange", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("napkin", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] napkin", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("mayo", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] mayo", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("lemon", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] lemon", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("kindle", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] kindle", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("jeep", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] jeep", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("ice", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] ice", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("haystack", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] haystack", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("granola", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] granola", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("fred", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] fred", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("elephant", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] elephant", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("dog", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] dog", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("cantaloupe", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] cantaloupe", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("banana", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] banana", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("apple", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] apple", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("secondInit", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] secondInit", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("init", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] init", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("go", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] go", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
+ EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT(!walker.Down());
}
}
@@ -2718,7 +2721,7 @@
EXPECT_EQ(table->FindCodeForPC(42), static_cast<ProfileCode*>(NULL));
int64_t timestamp = 0;
- Code& null_code = Code::Handle(Z);
+ const AbstractCode null_code(Code::null());
ProfileCode* code1 = new (Z)
ProfileCode(ProfileCode::kNativeCode, 50, 60, timestamp, null_code);
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 3ce3ced..d423f89 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -521,9 +521,8 @@
}
bool RawCode::ContainsPC(RawObject* raw_obj, uword pc) {
- uint32_t tags = raw_obj->ptr()->tags_;
- if (RawObject::ClassIdTag::decode(tags) == kCodeCid) {
- RawCode* raw_code = reinterpret_cast<RawCode*>(raw_obj);
+ if (raw_obj->IsCode()) {
+ RawCode* raw_code = static_cast<RawCode*>(raw_obj);
return RawInstructions::ContainsPC(raw_code->ptr()->instructions_, pc);
}
return false;
@@ -557,6 +556,17 @@
#endif
}
+bool RawBytecode::ContainsPC(RawObject* raw_obj, uword pc) {
+ if (raw_obj->IsBytecode()) {
+ RawBytecode* raw_bytecode = static_cast<RawBytecode*>(raw_obj);
+ RawExternalTypedData* bytes = raw_bytecode->ptr()->instructions_;
+ uword start = reinterpret_cast<uword>(bytes->ptr()->data_);
+ uword size = Smi::Value(bytes->ptr()->length_);
+ return (pc - start) < size;
+ }
+ return false;
+}
+
intptr_t RawObjectPool::VisitObjectPoolPointers(RawObjectPool* raw_obj,
ObjectPointerVisitor* visitor) {
const intptr_t length = raw_obj->ptr()->length_;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3b4717d..3e35ec4 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1490,6 +1490,8 @@
intptr_t source_positions_binary_offset_;
+ static bool ContainsPC(RawObject* raw_obj, uword pc);
+
friend class Function;
friend class StackFrame;
};
@@ -2395,6 +2397,8 @@
VISIT_TO(RawCompressed, length_)
uint8_t* data_;
+
+ friend class RawBytecode;
};
// VM implementations of the basic types in the isolate.
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 1f5782a..7e2cb38 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1864,6 +1864,10 @@
if (!code.IsNull()) {
return code.raw();
}
+ Bytecode& bytecode = Bytecode::Handle(Bytecode::FindCode(pc));
+ if (!bytecode.IsNull()) {
+ return bytecode.raw();
+ }
// Not found.
return Object::sentinel().raw();