voidScavenger::Scavenge(){ // Setup the visitor and run a scavenge. ScavengerVisitor visitor(this); Prologue(); IterateRoots(&visitor); ProcessToSpace(&visitor); Epilogue(); }
voidScavenger::Prologue(){ // Flip the two semi-spaces so that to_ is always the space for allocating // objects. MemoryRegion* temp = from_; from_ = to_; to_ = temp; }
// Fast exit if the raw object is a Smi. if (!raw_obj->IsHeapObject()) return;
uword raw_addr = RawObject::ToAddr(raw_obj); // Objects should be contained in the heap. // TODO(iposva): Add an appropriate assert here or in the return block // below. // The scavenger is only interested in objects located in the from space. if (!scavenger_->from_->Contains(raw_addr)) { // Addresses being visited cannot point in the to space. As this would // either mean the pointer is being visited twice or this pointer has not // been evacuated during the last scavenge. Both of these situations are // an error. ASSERT(!scavenger_->to_->Contains(raw_addr)); return; } } };
// TODO(iposva): This is a placeholder for the eventual external Dart API. DART_EXPORT boolDart_Initialize(int argc, char** argv, Dart_IsolateInitCallback callback){ return Dart::InitOnce(argc, argv, callback); }
OS初始化,设置了一个标志位,用于防止重复初始化;
虚拟内存初始化,获取内存页的大小;
Isolate初始化,创建线程key;
创建vm isolate并初始化;
将Isoalte::Current置空;
设置初始化回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// runtime/vm/dart.cc boolDart::InitOnce(int argc, char** argv, Dart_IsolateInitCallback callback){ OS::InitOnce(); VirtualMemory::InitOnce(); Isolate::InitOnce(); // Create the VM isolate and finish the VM initialization. { .. } Isolate::SetCurrent(NULL); // Unregister the VM isolate from this thread. Isolate::SetInitCallback(callback); returntrue; }
创建vm isolate并初始化:
新建一个vm_isolate;
初始化新Heap;
初始化新ObjectStore;
初始化Object;
初始化stub_code,生成stub_code代码;
初始化PortMap;
初始化Scanner;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// runtime/vm/dart.cc boolDart::InitOnce(int argc, char** argv, Dart_IsolateInitCallback callback){ // Create the VM isolate and finish the VM initialization. { ASSERT(vm_isolate_ == NULL); vm_isolate_ = Isolate::Init(); Zone zone; HandleScope handle_scope; Heap::Init(vm_isolate_); ObjectStore::Init(vm_isolate_); Object::InitOnce(); StubCode::InitOnce(); PortMap::InitOnce(); Scanner::InitOnce(); } }
// Give the embedder a shot at setting up this isolate. // Isolates spawned from within this isolate will be given the callback data // returned by the callback. data = Isolate::InitCallback()(data); // TODO(iposva): Shutdown the isolate on failure. isolate->set_init_callback_data(data); return isolate; }
staticvoid* MainIsolateInitCallback(void* data){ result = LoadScript(script_name); Dart_Handle library = Dart_GetResult(result); Builtin_ImportLibrary(library); // Setup the native resolver for built in library functions. Builtin_SetNativeResolver(); }
// Parser is at the opening parenthesis of the formal parameter declaration // of function. Parse the formal parameters and code. SequenceNode* Parser::ParseFunc(const Function& func, Array& default_parameter_values){ }
不优化的CodeGen–CodeGenerator。
通过宏隔离区分不同Target的实现。
1 2 3
TARGET_ARCH_IA32 TARGET_ARCH_ARM TARGET_ARCH_X64
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// NOTE: First 5 bytes of the code may be patched with a jump instruction. Do // not emit any objects in the first 5 bytes. voidCodeGenerator::GenerateCode(){ GeneratePreEntryCode(); GenerateEntryCode(); parsed_function_.node_sequence()->Visit(this); GenerateDeferredCode(); pc_descriptors_list_->AddDescriptor(PcDescriptors::kPatchCode, assembler_->CodeSize(), AstNode::kInvalidId, 0, -1); __ jmp(&StubCode::FixCallersTargetLabel()); }
// Pre entry code is called before the frame has been constructed: // - check for stack overflow. // - optionally count function invocations. // - optionally trigger optimizing compiler if invocation threshold has been // reached. // Note that first 5 bytes may be patched with a jump. // TODO(srdjan): Add check that no object is inlined in the first // 5 bytes (length of a jump instruction). voidCodeGenerator::GeneratePreEntryCode(){ if (may_optimize) { __ cmpl(EBX, Immediate(FLAG_optimization_invocation_threshold)); __ j(GREATER, &StubCode::OptimizeInvokedFunctionLabel()); } }
栈帧创建和参数处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Call to generate entry code: // - compute frame size and setup frame. // - allocate local variables on stack. // - optionally check if number of arguments match. // - initialize all non-argument locals to null. // // Input parameters: // ESP : points to return address. // ESP + 4 : address of last argument (arg n-1). // ESP + 4*n : address of first argument (arg 0). // EDX : arguments descriptor array. voidCodeGenerator::GenerateEntryCode(){
voidCodeGenerator::VisitLoadLocalNode(LoadLocalNode* node){ // Load the value of the local variable and push it onto the expression stack. if (IsResultNeeded(node)) { GeneratePushVariable(node->local(), EAX); } }
oid CodeGenerator::GeneratePushVariable(const LocalVariable& variable, Register scratch){ if (variable.is_captured()) { // The variable lives in the context. int delta = state()->context_level() - variable.owner()->context_level(); ASSERT(delta >= 0); Register base = CTX; while (delta-- > 0) { __ movl(scratch, FieldAddress(base, Context::parent_offset())); base = scratch; } __ pushl(FieldAddress(base, Context::variable_offset(variable.index()))); } else { // The variable lives in the current stack frame. __ pushl(Address(EBP, variable.index() * kWordSize)); } }
voidCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node){ constint number_of_arguments = node->arguments()->length() + 1; // Compute the receiver object and pass it as first argument to call. node->receiver()->Visit(this); // Now compute rest of the arguments to the call. node->arguments()->Visit(this); // Some method may be inlined using type feedback, therefore this may be a // deoptimization point. MarkDeoptPoint(node->id(), node->token_index());
GenerateInstanceCall(node->id(), node->token_index(), node->function_name(), number_of_arguments, node->arguments()); // Result is in EAX. if (IsResultNeeded(node)) { __ pushl(EAX); } }
inline cache调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
voidCodeGenerator::GenerateInstanceCall(intptr_t node_id, intptr_t token_index, const String& function_name, int arg_count, ArgumentListNode* arguments){ // Set up the function name and number of arguments (including the receiver) // to the InstanceCall stub which will resolve the correct entrypoint for // the operator and call it. __ LoadObject(ECX, function_name); __ LoadObject(EDX, ArgumentsDescriptor(arg_count, arguments)); __ call(&StubCode::CallInstanceFunctionLabel()); AddCurrentDescriptor(PcDescriptors::kIcCall, node_id, token_index); __ addl(ESP, Immediate(arg_count * kWordSize)); }
// Resolve instance call and patch it to jump to IC stub or megamorphic stub. // After patching the caller's instance call instruction, that call will // be reexecuted and ran through the created IC stub. The null receivers // have special handling, i.e., they lead to megamorphic lookup that implements // the appropriate null behavior. // Arg0: receiver object. DEFINE_RUNTIME_ENTRY(ResolvePatchInstanceCall, 1) { const Instance& receiver = Instance::CheckedHandle(arguments.At(0)); const Code& code = Code::Handle(ResolveCompileInstanceCallTarget(receiver)); DartFrameIterator iterator; DartFrame* caller_frame = iterator.NextFrame(); String& function_name = String::Handle(); if ((!receiver.IsNull() && code.IsNull()) || !FLAG_inline_cache) { } else { CodePatcher::GetInstanceCallAt(caller_frame->pc(), &function_name, &num_arguments, &num_named_arguments, &caller_target); // If caller_target is not in CallInstanceFunction stub (resolve call) // then it must be pointing to an IC stub. const Class& receiver_class = Class::ZoneHandle(receiver.clazz()); const Code& ic_code = Code::Handle(ICStubs::GetICStub(classes, targets)); CodePatcher::PatchInstanceCallAt(caller_frame->pc(), ic_code.EntryPoint()); } }
// Generate inline cache stub for given targets and classes. // EDX: arguments descriptor array (preserved). // ECX: function name (unused, preserved). // TOS: return address. // Jump to target if the receiver's class matches the 'receiver_class'. // Otherwise jump to megamorphic lookup. TODO(srdjan): Patch call site to go to // megamorphic instead of going via the IC stub. // IC stub structure: // A: Get receiver, test if Smi, jump to IC miss or hit. // B: Get receiver's class, compare with all known classes. RawCode* ICStubs::GetICStub(const GrowableArray<const Class*>& classes, const GrowableArray<const Function*>& targets){
}
优化代码生成器–OptimizingCodeGenerator
继承自CodeGenerator,在一些Node实现上进行扩展,生成更高效的代码。
1 2 3 4 5 6 7 8 9
voidOptimizingCodeGenerator::VisitLoadLocalNode(LoadLocalNode* node){ if (!IsResultNeeded(node)) return; if (IsResultInEaxRequested(node)) { GenerateLoadVariable(EAX, node->local()); node->info()->set_result_returned_in_eax(true); } else { GeneratePushVariable(node->local(), EAX); } }
在优化生成器中会有退优化的操作。首先是生成检查点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// TODO(srdjan): Expand inline caches to detect Smi/double operations, so that // we do not have to call the instance method, and therefore could guarantee // that the result is a Smi at the end. voidOptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node){ if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); overflow_label = deopt_blob->label(); __ movl(ECX, EAX); // Save if overflow (needs original value). if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) { Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX; __ testl(test_reg, Immediate(kSmiTagMask)); __ j(NOT_ZERO, deopt_blob->label()); } } }
voidOptimizingCodeGenerator::GenerateDeferredCode(){ CodeGenerator::GenerateDeferredCode(); for (int i = 0; i < deoptimization_blobs_.length(); i++) { deoptimization_blobs_[i]->Generate(this); } }
// Code that calls the deoptimizer, emitted as deferred code (out of line). // Specify the corresponding 'node' and the registers that need to // be pushed for the deoptimization point in unoptimized code. classDeoptimizationBlob : public ZoneAllocated { voidGenerate(OptimizingCodeGenerator* codegen){ codegen->assembler()->Bind(&label_); for (int i = 0; i < registers_.length(); i++) { codegen->assembler()->pushl(registers_[i]); } codegen->CallDeoptimize(node_->id(), node_->token_index()); } };
// runtime/vm/resolver.cc RawFunction* Resolver::ResolveStatic(const Library& library, const String& class_name, const String& function_name, int num_arguments, const Array& argument_names, StaticResolveType resolve_type){ if (class_name.IsNull() || (class_name.Length() == 0)) { // Check if we are referring to a top level function. const Object& object = Object::Handle(library.LookupObject(function_name)); } else { // Lookup class_name in the library's class dictionary to get at // the dart class object. If class_name is not found in the dictionary // ResolveStatic will return a NULL function object. const Class& cls = Class::Handle(library.LookupClass(class_name)); function = ResolveStatic(cls, function_name, num_arguments, argument_names, resolve_type); } return function.raw(); }
先在当前库中查找符号,找不到在遍历import的库进行查找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
RawObject* Library::LookupObject(const String& name)const{ Object& obj = Object::Handle(LookupLocalObject(name)); if (!obj.IsNull()) { return obj.raw(); } Library& import = Library::Handle(); Array& imports = Array::Handle(this->imports()); for (intptr_t i = 0; i < num_imports(); i++) { import ^= imports.At(i); obj = import.LookupLocalObject(name); if (!obj.IsNull()) { return obj.raw(); } } return Object::null(); }
RawObject* Library::LookupLocalObject(const String& name)const{ const Array& dict = Array::Handle(dictionary()); intptr_t dict_size = dict.Length() - 1; intptr_t index = name.Hash() % dict_size; entry = dict.At(index); // Search the entry in the hash set. while (!entry.IsNull()) { if (entry.IsFunction()) { func ^= entry.raw(); entry_name = func.name(); } if (entry_name.Equals(name)) { return entry.raw(); } index = (index + 1) % dict_size; entry = dict.At(index); } }
调用函数。
1 2 3 4 5 6 7 8 9 10
// NOTE: Need to pass 'result' as a parameter here in order to avoid // warning: variable 'result' might be clobbered by 'longjmp' or 'vfork' // which shows up because of the use of setjmp. staticvoidInvokeStatic(const Function& function, GrowableArray<const Object*>& args, Dart_Result* result){ const Instance& retval = Instance::Handle(DartEntry::InvokeStatic(function, args)); result->type_ = kRetObject; result->retval_.obj_value = Api::NewLocalHandle(retval); }
// runtime/vm/dart_entry.cc RawInstance* DartEntry::InvokeStatic( const Function& function, const GrowableArray<const Object*>& arguments){ // Get the entrypoint corresponding to the function specified, this // will result in a compilation of the function if it is not already // compiled. if (!function.HasCode()) { Compiler::CompileFunction(function); } const Code& code = Code::Handle(function.code()); const Instructions& instrs = Instructions::Handle(code.instructions()); // Now Call the invoke stub which will invoke the dart function. invokestub entrypoint = reinterpret_cast<invokestub>( StubCode::InvokeDartCodeEntryPoint()); const Context& context = Context::ZoneHandle(Isolate::Current()->object_store()->empty_context()); returnentrypoint( instrs.EntryPoint(), CodeGenerator::ArgumentsDescriptor(arguments.length(), NULL), arguments.data(), context); }
// runtime/vm/stub_code.h // List of stubs created per isolate, these stubs could potentially contain // embedded objects and hence cannot be shared across isolates. #define STUB_CODE_LIST(V) \ V(InvokeDartCode) \ V(AllocateContext) \ // class StubCode is used to maintain the lifecycle of stubs. classStubCode { // Define the per-isolate stub code accessors. #define STUB_CODE_ACCESSOR(name) \ static StubEntry* name##_entry() { \ return Isolate::Current()->stub_code()->name##_entry_; \ } \ static uword name##EntryPoint() { \ return name##_entry()->EntryPoint(); \ } \ static intptr_t name##Size() { \ return name##_entry()->Size(); \ } STUB_CODE_LIST(STUB_CODE_ACCESSOR); #undef STUB_CODE_ACCESSOR };
1 2 3 4 5 6 7 8 9 10 11 12
// Called when invoking dart code from C++ (VM code). // Input parameters: // ESP : points to return address. // ESP + 4 : entrypoint of the dart function to call. // ESP + 8 : arguments descriptor array. // ESP + 12 : pointer to the argument array. // ESP + 16 : new context containing the current isolate pointer. // Uses EAX, EDX, ECX, EDI as temporary registers. voidStubCode::GenerateInvokeDartCodeStub(Assembler* assembler){ // Call the dart code entrypoint. __ call(Address(EBP, kEntryPointOffset)); }
gen_snapshot执行过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intmain(int argc, char** argv){ // Initialize the Dart VM. Dart_Initialize(vm_options.count(), vm_options.arguments(), SnapshotCreateCallback); // Create an isolate. As a side effect, SnapshotCreateCallback // gets called, which loads the script (if one is specified), its libraries // and writes out a snapshot. Dart_Isolate isolate = Dart_CreateIsolate(NULL, script_name); // Shutdown the isolate. Dart_ShutdownIsolate(); return0; }
执行环境初始化,然后调用回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
DART_EXPORT Dart_Isolate Dart_CreateIsolate(void* snapshot, void* data){ // Create and initialize a new isolate. Isolate* isolate = Isolate::Init(); Zone zone; HandleScope handle_scope; Heap::Init(isolate); ObjectStore::Init(isolate); Object::Init(isolate); StubCode::Init(isolate); CodeIndexTable::Init(isolate);
// Give the embedder a shot at setting up this isolate. // Isolates spawned from within this isolate will be given the callback data // returned by the callback. data = Isolate::InitCallback()(data); // TODO(iposva): Shutdown the isolate on failure. isolate->set_init_callback_data(data); return isolate; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// runtime/bin/gen_snapshot.cc staticvoid* SnapshotCreateCallback(void* data){ constchar* script_name = reinterpret_cast<constchar*>(data) Dart_EnterScope(); result = LoadScript(script_name); Dart_Handle library = Dart_GetResult(result); Builtin_ImportLibrary(library); // Setup the native resolver for built in library functions. Builtin_SetNativeResolver(); // First create the snapshot. result = Dart_CreateSnapshot(&buffer, &size); // Now write the snapshot out to specified file and exit. WriteSnapshotFile(buffer, size); Dart_ExitScope(); return data; }
voidScavenger::Scavenge(){ // Setup the visitor and run a scavenge. ScavengerVisitor visitor(this); Prologue(); IterateRoots(&visitor); ProcessToSpace(&visitor); Epilogue(); }
enum class GCType { kScavenge, kEvacuate, kStartConcurrentMark, kMarkSweep, kMarkCompact, };
enum class GCReason { kNewSpace, // New space is full. kStoreBuffer, // Store buffer is too big. kPromotion, // Old space limit crossed after a scavenge. kOldSpace, // Old space limit crossed, or old space allocation failed. kFinalize, // Concurrent marking finished. kFull, // Heap::CollectAllGarbage kExternal, // Dart_NewFinalizableHandle Dart_NewWeakPersistentHandle kIdle, // Dart_NotifyIdle kDestroyed, // Dart_NotifyDestroyed kDebugging, // service request, etc. kCatchUp, // End of ForceGrowthScope or Dart_PerformanceMode_Latency. };