| Index: runtime/vm/precompiler.cc
|
| diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
|
| index 7000601bc549cc3da0aa236ab80d47122d4d798b..b69300250b85d153ad973905aedac3ef3e8e1f2a 100644
|
| --- a/runtime/vm/precompiler.cc
|
| +++ b/runtime/vm/precompiler.cc
|
| @@ -60,35 +60,35 @@ Precompiler::Precompiler(Thread* thread, bool reset_fields) :
|
| libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())),
|
| pending_functions_(
|
| GrowableObjectArray::Handle(Z, GrowableObjectArray::New())),
|
| - collected_closures_(
|
| - GrowableObjectArray::Handle(Z, GrowableObjectArray::New())),
|
| sent_selectors_(),
|
| + enqueued_functions_(),
|
| error_(Error::Handle(Z)) {
|
| - I->set_collected_closures(collected_closures_);
|
| }
|
|
|
|
|
| void Precompiler::DoCompileAll(
|
| Dart_QualifiedFunctionName embedder_entry_points[]) {
|
| - // Drop all existing code so we can use the presence of code as an indicator
|
| - // that we have already looked for the function's callees.
|
| ClearAllCode();
|
|
|
| // Make sure class hierarchy is stable before compilation so that CHA
|
| - // can be used.
|
| + // can be used. Also ensures lookup of entry points won't miss functions
|
| + // because their class hasn't been finalized yet.
|
| FinalizeAllClasses();
|
|
|
| // Start with the allocations and invocations that happen from C++.
|
| AddRoots(embedder_entry_points);
|
|
|
| - // TODO(rmacnak): Eagerly add field-invocation functions to all signature
|
| - // classes so closure calls don't go through the runtime.
|
| -
|
| // Compile newly found targets and add their callees until we reach a fixed
|
| // point.
|
| Iterate();
|
|
|
| - CleanUp();
|
| + DropUncompiledFunctions();
|
| +
|
| + // TODO(rmacnak): DropEmptyClasses();
|
| +
|
| + BindStaticCalls();
|
| +
|
| + DedupStackmaps();
|
|
|
| if (FLAG_trace_precompiler) {
|
| THR_Print("Precompiled %" Pd " functions, %" Pd " dynamic types,"
|
| @@ -191,6 +191,7 @@ void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) {
|
|
|
| Dart_QualifiedFunctionName vm_entry_points[] = {
|
| { "dart:async", "::", "_setScheduleImmediateClosure" },
|
| + { "dart:core", "::", "_completeDeferredLoads"},
|
| { "dart:core", "AbstractClassInstantiationError",
|
| "AbstractClassInstantiationError._create" },
|
| { "dart:core", "ArgumentError", "ArgumentError." },
|
| @@ -297,30 +298,10 @@ void Precompiler::Iterate() {
|
| }
|
|
|
| CheckForNewDynamicFunctions();
|
| -
|
| - // Drain collected_closures last because additions to this list come from
|
| - // outside the Precompiler and so do not flip our changed_ flag.
|
| - while (collected_closures_.Length() > 0) {
|
| - function ^= collected_closures_.RemoveLast();
|
| - ProcessFunction(function);
|
| - }
|
| }
|
| }
|
|
|
|
|
| -void Precompiler::CleanUp() {
|
| - I->set_collected_closures(GrowableObjectArray::Handle(Z));
|
| -
|
| - DropUncompiledFunctions();
|
| -
|
| - // TODO(rmacnak): DropEmptyClasses();
|
| -
|
| - BindStaticCalls();
|
| -
|
| - DedupStackmaps();
|
| -}
|
| -
|
| -
|
| void Precompiler::ProcessFunction(const Function& function) {
|
| if (!function.HasCode()) {
|
| function_count_++;
|
| @@ -372,6 +353,8 @@ void Precompiler::AddCalleesOf(const Function& function) {
|
| String& selector = String::Handle(Z);
|
| Field& field = Field::Handle(Z);
|
| Class& cls = Class::Handle(Z);
|
| + Instance& instance = Instance::Handle(Z);
|
| + Code& target_code = Code::Handle(Z);
|
| for (intptr_t i = 0; i < pool.Length(); i++) {
|
| if (pool.InfoAt(i) == ObjectPool::kTaggedObject) {
|
| entry = pool.ObjectAt(i);
|
| @@ -401,15 +384,71 @@ void Precompiler::AddCalleesOf(const Function& function) {
|
| field ^= entry.raw();
|
| AddField(field);
|
| } else if (entry.IsInstance()) {
|
| - // Potential const object.
|
| - cls = entry.clazz();
|
| - AddClass(cls);
|
| + // Const object, literal or args descriptor.
|
| + instance ^= entry.raw();
|
| + AddConstObject(instance);
|
| + } else if (entry.IsFunction()) {
|
| + // Local closure function.
|
| + target ^= entry.raw();
|
| + AddFunction(target);
|
| + } else if (entry.IsCode()) {
|
| + target_code ^= entry.raw();
|
| + if (target_code.IsAllocationStubCode()) {
|
| + cls ^= target_code.owner();
|
| + AddClass(cls);
|
| + }
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
| +void Precompiler::AddConstObject(const Instance& instance) {
|
| + const Class& cls = Class::Handle(Z, instance.clazz());
|
| + AddClass(cls);
|
| +
|
| + if (instance.IsClosure()) {
|
| + // An implicit static closure.
|
| + const Function& func = Function::Handle(Z, Closure::function(instance));
|
| + ASSERT(func.is_static());
|
| + AddFunction(func);
|
| + return;
|
| + }
|
| +
|
| + // Can't ask immediate objects if they're canoncial.
|
| + if (instance.IsSmi()) return;
|
| +
|
| + // Some Instances in the ObjectPool aren't const objects, such as
|
| + // argument descriptors.
|
| + if (!instance.IsCanonical()) return;
|
| +
|
| + class ConstObjectVisitor : public ObjectPointerVisitor {
|
| + public:
|
| + ConstObjectVisitor(Precompiler* precompiler, Isolate* isolate) :
|
| + ObjectPointerVisitor(isolate),
|
| + precompiler_(precompiler),
|
| + subinstance_(Object::Handle()) {}
|
| +
|
| + virtual void VisitPointers(RawObject** first, RawObject** last) {
|
| + for (RawObject** current = first; current <= last; current++) {
|
| + subinstance_ = *current;
|
| + if (subinstance_.IsInstance()) {
|
| + precompiler_->AddConstObject(Instance::Cast(subinstance_));
|
| + }
|
| + }
|
| + subinstance_ = Object::null();
|
| + }
|
| +
|
| + private:
|
| + Precompiler* precompiler_;
|
| + Object& subinstance_;
|
| + };
|
| +
|
| + ConstObjectVisitor visitor(this, I);
|
| + instance.raw()->VisitPointers(&visitor);
|
| +}
|
| +
|
| +
|
| void Precompiler::AddClosureCall(const ICData& call_site) {
|
| const Array& arguments_descriptor =
|
| Array::Handle(Z, call_site.arguments_descriptor());
|
| @@ -428,11 +467,10 @@ void Precompiler::AddClosureCall(const ICData& call_site) {
|
|
|
| void Precompiler::AddField(const Field& field) {
|
| if (field.is_static()) {
|
| - // Potential const object. Uninitialized field will harmlessly do a
|
| - // redundant add of the Null class.
|
| const Object& value = Object::Handle(Z, field.StaticValue());
|
| - const Class& cls = Class::Handle(Z, value.clazz());
|
| - AddClass(cls);
|
| + if (value.IsInstance()) {
|
| + AddConstObject(Instance::Cast(value));
|
| + }
|
|
|
| if (field.has_initializer()) {
|
| // Should not be in the middle of initialization while precompiling.
|
| @@ -459,8 +497,9 @@ void Precompiler::AddField(const Field& field) {
|
|
|
|
|
| void Precompiler::AddFunction(const Function& function) {
|
| - if (function.HasCode()) return;
|
| + if (enqueued_functions_.Lookup(&function) != NULL) return;
|
|
|
| + enqueued_functions_.Insert(&Function::ZoneHandle(Z, function.raw()));
|
| pending_functions_.Add(function);
|
| changed_ = true;
|
| }
|
| @@ -525,43 +564,7 @@ void Precompiler::CheckForNewDynamicFunctions() {
|
| while (it.HasNext()) {
|
| cls = it.GetNextClass();
|
|
|
| - if (!cls.is_allocated()) {
|
| - bool has_compiled_constructor = false;
|
| - if (cls.allocation_stub() != Code::null()) {
|
| - // Regular objects.
|
| - has_compiled_constructor = true;
|
| - } else if (cls.is_synthesized_class()) {
|
| - // Enums.
|
| - has_compiled_constructor = true;
|
| - } else {
|
| - // Objects only allocated via const constructors, and not stored in a
|
| - // static field or code.
|
| - // E.g. A in
|
| - // class A {
|
| - // const A();
|
| - // toString() => "Don't drop me!";
|
| - // }
|
| - // class B {
|
| - // const a = const A();
|
| - // const B();
|
| - // static const theB = const B();
|
| - // }
|
| - // main() => print(B.theB.a);
|
| - functions = cls.functions();
|
| - for (intptr_t k = 0; k < functions.Length(); k++) {
|
| - function ^= functions.At(k);
|
| - if (function.IsGenerativeConstructor() &&
|
| - function.HasCode()) {
|
| - has_compiled_constructor = true;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - if (!has_compiled_constructor) {
|
| - continue;
|
| - }
|
| - AddClass(cls);
|
| - }
|
| + if (!cls.is_allocated()) continue;
|
|
|
| functions = cls.functions();
|
| for (intptr_t k = 0; k < functions.Length(); k++) {
|
| @@ -816,6 +819,10 @@ void Precompiler::VisitFunctions(FunctionVisitor* visitor) {
|
| for (intptr_t j = 0; j < functions.Length(); j++) {
|
| function ^= functions.At(j);
|
| visitor->VisitFunction(function);
|
| + if (function.HasImplicitClosureFunction()) {
|
| + function = function.ImplicitClosureFunction();
|
| + visitor->VisitFunction(function);
|
| + }
|
| }
|
|
|
| closures = cls.closures();
|
|
|