From d94b68cb41d5b6cb9a4c536c19911bac4f1f5b9a Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Thu, 3 Dec 2015 11:03:23 -0800 Subject: [PATCH] Precompilation: Don't drop an uncompiled function if it has a compiled implicit closure function. This ensures the implicit closure function is enumerated in later steps. Fixes crash in co19 test reducible as import 'dart:math'; main() { print(const [1, 2.0, "3"].fold(0, max)); } Also enumerate invocation dispatchers to avoid a similar situation there, though I cannot find a crashing example involving them. R=fschneider@google.com Review URL: https://codereview.chromium.org/1489203004 . --- runtime/vm/object.h | 1 + runtime/vm/precompiler.cc | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 67bb1866484..2bf1aa2a26d 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -1485,6 +1485,7 @@ class Class : public Object { friend class Object; friend class Type; friend class Intrinsifier; + friend class Precompiler; }; diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc index a990a089860..c691a807f2f 100644 --- a/runtime/vm/precompiler.cc +++ b/runtime/vm/precompiler.cc @@ -713,6 +713,7 @@ void Precompiler::DropUncompiledFunctions() { Class& cls = Class::Handle(Z); Array& functions = Array::Handle(Z); Function& function = Function::Handle(Z); + Function& function2 = Function::Handle(Z); GrowableObjectArray& retained_functions = GrowableObjectArray::Handle(Z); GrowableObjectArray& closures = GrowableObjectArray::Handle(Z); @@ -729,7 +730,16 @@ void Precompiler::DropUncompiledFunctions() { retained_functions = GrowableObjectArray::New(); for (intptr_t j = 0; j < functions.Length(); j++) { function ^= functions.At(j); - if (function.HasCode()) { + bool retain = function.HasCode(); + if (!retain && function.HasImplicitClosureFunction()) { + // It can happen that all uses of an implicit closure inline their + // target function, leaving the target function uncompiled. Keep + // the target function anyway so we can enumerate it to bind its + // static calls, etc. + function2 = function.ImplicitClosureFunction(); + retain = function2.HasCode(); + } + if (retain) { retained_functions.Add(function); function.DropUncompiledImplicitClosureFunction(); } else { @@ -780,7 +790,10 @@ void Precompiler::BindStaticCalls() { } void VisitFunction(const Function& function) { - ASSERT(function.HasCode()); + if (!function.HasCode()) { + ASSERT(function.HasImplicitClosureFunction()); + return; + } code_ = function.CurrentCode(); table_ = code_.static_calls_target_table(); @@ -837,6 +850,10 @@ void Precompiler::DedupStackmaps() { } void VisitFunction(const Function& function) { + if (!function.HasCode()) { + ASSERT(function.HasImplicitClosureFunction()); + return; + } code_ = function.CurrentCode(); stackmaps_ = code_.stackmaps(); if (stackmaps_.IsNull()) return; @@ -876,6 +893,7 @@ void Precompiler::VisitFunctions(FunctionVisitor* visitor) { Library& lib = Library::Handle(Z); Class& cls = Class::Handle(Z); Array& functions = Array::Handle(Z); + Object& object = Object::Handle(Z); Function& function = Function::Handle(Z); GrowableObjectArray& closures = GrowableObjectArray::Handle(Z); @@ -897,6 +915,15 @@ void Precompiler::VisitFunctions(FunctionVisitor* visitor) { visitor->VisitFunction(function); } } + + functions = cls.invocation_dispatcher_cache(); + for (intptr_t j = 0; j < functions.Length(); j++) { + object = functions.At(j); + if (object.IsFunction()) { + function ^= functions.At(j); + visitor->VisitFunction(function); + } + } } } closures = isolate()->object_store()->closure_functions();