| // Copyright (c) 2012, 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/stub_code.h" |
| |
| #include "platform/assert.h" |
| #include "platform/globals.h" |
| #include "vm/assembler.h" |
| #include "vm/disassembler.h" |
| #include "vm/flags.h" |
| #include "vm/object_store.h" |
| #include "vm/virtual_memory.h" |
| #include "vm/visitor.h" |
| |
| namespace dart { |
| |
| DEFINE_FLAG(bool, disassemble_stubs, false, "Disassemble generated stubs."); |
| |
| #define STUB_CODE_DECLARE(name) \ |
| StubEntry* StubCode::name##_entry_ = NULL; |
| VM_STUB_CODE_LIST(STUB_CODE_DECLARE); |
| #undef STUB_CODE_DECLARE |
| |
| |
| StubEntry::StubEntry(const Code& code) |
| : code_(code.raw()), |
| entry_point_(code.EntryPoint()), |
| size_(code.Size()), |
| label_(code.EntryPoint()) { |
| } |
| |
| |
| // Visit all object pointers. |
| void StubEntry::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| ASSERT(visitor != NULL); |
| visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_)); |
| } |
| |
| |
| StubCode::~StubCode() { |
| #define STUB_CODE_DELETER(name) \ |
| delete name##_entry_; |
| STUB_CODE_LIST(STUB_CODE_DELETER); |
| #undef STUB_CODE_DELETER |
| } |
| |
| |
| #define STUB_CODE_GENERATE(name) \ |
| code ^= Generate("_stub_"#name, StubCode::Generate##name##Stub); \ |
| name##_entry_ = new StubEntry(code); |
| |
| |
| void StubCode::InitOnce() { |
| // Generate all the stubs. |
| Code& code = Code::Handle(); |
| VM_STUB_CODE_LIST(STUB_CODE_GENERATE); |
| } |
| |
| |
| void StubCode::GenerateBootstrapStubsFor(Isolate* init) { |
| // Generate initial stubs. |
| Code& code = Code::Handle(); |
| BOOTSTRAP_STUB_CODE_LIST(STUB_CODE_GENERATE); |
| } |
| |
| |
| void StubCode::GenerateStubsFor(Isolate* init) { |
| // Generate all the other stubs. |
| Code& code = Code::Handle(); |
| REST_STUB_CODE_LIST(STUB_CODE_GENERATE); |
| } |
| |
| #undef STUB_CODE_GENERATE |
| |
| |
| void StubCode::InitBootstrapStubs(Isolate* isolate) { |
| StubCode* stubs = new StubCode(isolate); |
| isolate->set_stub_code(stubs); |
| stubs->GenerateBootstrapStubsFor(isolate); |
| } |
| |
| |
| void StubCode::Init(Isolate* isolate) { |
| isolate->stub_code()->GenerateStubsFor(isolate); |
| } |
| |
| |
| void StubCode::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| // The current isolate is needed as part of the macro. |
| Isolate* isolate = Isolate::Current(); |
| StubCode* stubs = isolate->stub_code(); |
| if (stubs == NULL) return; |
| StubEntry* entry; |
| #define STUB_CODE_VISIT_OBJECT_POINTER(name) \ |
| entry = stubs->name##_entry(); \ |
| if (entry != NULL) { \ |
| entry->VisitObjectPointers(visitor); \ |
| } |
| |
| STUB_CODE_LIST(STUB_CODE_VISIT_OBJECT_POINTER); |
| #undef STUB_CODE_VISIT_OBJECT_POINTER |
| } |
| |
| |
| bool StubCode::InInvocationStub(uword pc) { |
| return InInvocationStubForIsolate(Isolate::Current(), pc); |
| } |
| |
| |
| bool StubCode::InInvocationStubForIsolate(Isolate* isolate, uword pc) { |
| StubCode* stub_code = isolate->stub_code(); |
| uword entry = stub_code->InvokeDartCodeEntryPoint(); |
| uword size = stub_code->InvokeDartCodeSize(); |
| return (pc >= entry) && (pc < (entry + size)); |
| } |
| |
| |
| bool StubCode::InJumpToExceptionHandlerStub(uword pc) { |
| uword entry = StubCode::JumpToExceptionHandlerEntryPoint(); |
| uword size = StubCode::JumpToExceptionHandlerSize(); |
| return (pc >= entry) && (pc < (entry + size)); |
| } |
| |
| |
| RawCode* StubCode::GetAllocateArrayStub() { |
| const Class& array_cls = Class::Handle(isolate_, |
| isolate_->object_store()->array_class()); |
| return GetAllocationStubForClass(array_cls); |
| } |
| |
| |
| RawCode* StubCode::GetAllocationStubForClass(const Class& cls) { |
| Isolate* isolate = Isolate::Current(); |
| const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate)); |
| ASSERT(error.IsNull()); |
| Code& stub = Code::Handle(isolate, cls.allocation_stub()); |
| if (stub.IsNull()) { |
| Assembler assembler; |
| const char* name = cls.ToCString(); |
| uword patch_code_offset = 0; |
| uword entry_patch_offset = 0; |
| if (cls.id() == kArrayCid) { |
| StubCode::GeneratePatchableAllocateArrayStub( |
| &assembler, &entry_patch_offset, &patch_code_offset); |
| } else { |
| StubCode::GenerateAllocationStubForClass( |
| &assembler, cls, &entry_patch_offset, &patch_code_offset); |
| } |
| stub ^= Code::FinalizeCode(name, &assembler); |
| stub.set_owner(cls); |
| cls.set_allocation_stub(stub); |
| if (FLAG_disassemble_stubs) { |
| OS::Print("Code for allocation stub '%s': {\n", name); |
| DisassembleToStdout formatter; |
| stub.Disassemble(&formatter); |
| OS::Print("}\n"); |
| } |
| stub.set_entry_patch_pc_offset(entry_patch_offset); |
| stub.set_patch_code_pc_offset(patch_code_offset); |
| } |
| return stub.raw(); |
| } |
| |
| |
| uword StubCode::UnoptimizedStaticCallEntryPoint(intptr_t num_args_tested) { |
| switch (num_args_tested) { |
| case 0: |
| return ZeroArgsUnoptimizedStaticCallEntryPoint(); |
| case 1: |
| return OneArgUnoptimizedStaticCallEntryPoint(); |
| case 2: |
| return TwoArgsUnoptimizedStaticCallEntryPoint(); |
| default: |
| UNIMPLEMENTED(); |
| return 0; |
| } |
| } |
| |
| |
| RawCode* StubCode::Generate(const char* name, |
| void (*GenerateStub)(Assembler* assembler)) { |
| Assembler assembler; |
| GenerateStub(&assembler); |
| const Code& code = Code::Handle(Code::FinalizeCode(name, &assembler)); |
| if (FLAG_disassemble_stubs) { |
| OS::Print("Code for stub '%s': {\n", name); |
| DisassembleToStdout formatter; |
| code.Disassemble(&formatter); |
| OS::Print("}\n"); |
| } |
| return code.raw(); |
| } |
| |
| |
| const char* StubCode::NameOfStub(uword entry_point) { |
| #define VM_STUB_CODE_TESTER(name) \ |
| if ((name##_entry() != NULL) && (entry_point == name##EntryPoint())) { \ |
| return ""#name; \ |
| } |
| VM_STUB_CODE_LIST(VM_STUB_CODE_TESTER); |
| |
| #define STUB_CODE_TESTER(name) \ |
| if ((isolate->stub_code()->name##_entry() != NULL) && \ |
| (entry_point == isolate->stub_code()->name##EntryPoint())) { \ |
| return ""#name; \ |
| } |
| Isolate* isolate = Isolate::Current(); |
| if ((isolate != NULL) && (isolate->stub_code() != NULL)) { |
| STUB_CODE_LIST(STUB_CODE_TESTER); |
| } |
| #undef VM_STUB_CODE_TESTER |
| #undef STUB_CODE_TESTER |
| return NULL; |
| } |
| |
| } // namespace dart |