[kernel/vm] Update closure conversion to work in Dart 2.

The change to vm.dart which turns it on by default will *not* be committed.

Change-Id: Ia3a80ff8e5335aa326f1ffaa9f5c9728ad511b60
Reviewed-on: https://dart-review.googlesource.com/51721
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
This commit is contained in:
Samir Jindel 2018-04-19 16:04:08 +00:00 committed by commit-bot@chromium.org
parent 6a8cad4877
commit 7e64ddd00f
7 changed files with 160 additions and 127 deletions

View file

@ -3650,9 +3650,23 @@ class VectorCopy extends Expression {
}
}
/// Expression of the form `MakeClosure(f, c, t)` where `f` is a name of a
/// closed top-level function, `c` is a Vector representing closure context, and
/// `t` is the type of the resulting closure.
/// Expression of the form `MakeClosure<T>(f, c, t)` where `f` is a name of a
/// closed top-level function, `c` is a Vector representing closure context, `t`
/// is the type of the resulting closure and `T` is a vector of type arguments
/// to be passed to `f`.
///
/// Note these restrictions on its usage:
///
/// 1. `f` must reference a statically-resolved top-level function.
///
/// 2. The length of `T` must be less than or equal to the number of type
/// parameters on `f`.
///
/// 3. It is disallowed to use `MakeClosure` on the same function twice with
/// different numbers of type arguments.
///
/// 4. The type arguments `T` must be guaranteed to satisfy the bounds of the
/// corresponding type parameters on `f`.
class ClosureCreation extends Expression {
Reference topLevelFunctionReference;
Expression contextVector;

View file

@ -894,7 +894,8 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() {
scope_->set_end_token_pos(function.end_token_pos());
// Add function type arguments variable before current context variable.
if (I->reify_generic_functions() && function.IsGeneric()) {
if (I->reify_generic_functions() &&
(function.IsGeneric() || function.HasGenericParent())) {
LocalVariable* type_args_var = MakeVariable(
TokenPosition::kNoSource, TokenPosition::kNoSource,
Symbols::FunctionTypeArgumentsVar(), AbstractType::dynamic_type());
@ -4713,55 +4714,58 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(bool constructor) {
Fragment body;
if (dart_function.IsConvertedClosureFunction()) {
LocalVariable* closure = new (Z) LocalVariable(
LocalVariable* closure = NULL;
if (dart_function.IsClosureFunction()) {
closure = parsed_function()->node_sequence()->scope()->VariableAt(0);
} else if (dart_function.IsConvertedClosureFunction()) {
closure = new (Z) LocalVariable(
TokenPosition::kNoSource, TokenPosition::kNoSource,
Symbols::TempParam(), AbstractType::ZoneHandle(Z, Type::DynamicType()));
closure->set_index(parsed_function()->first_parameter_index());
closure->set_is_captured_parameter(true);
}
if ((dart_function.IsClosureFunction() ||
dart_function.IsConvertedClosureFunction()) &&
dart_function.NumParentTypeParameters() > 0 &&
I->reify_generic_functions()) {
LocalVariable* fn_type_args = parsed_function()->function_type_arguments();
ASSERT(fn_type_args != NULL && closure != NULL);
if (dart_function.IsGeneric()) {
body += LoadLocal(fn_type_args);
body += PushArgument();
body += LoadLocal(closure);
body += LoadField(Closure::function_type_arguments_offset());
body += PushArgument();
body += IntConstant(dart_function.NumTypeParameters() +
dart_function.NumParentTypeParameters());
body += PushArgument();
const Library& dart_internal =
Library::Handle(Z, Library::InternalLibrary());
const Function& prepend_function =
Function::ZoneHandle(Z, dart_internal.LookupFunctionAllowPrivate(
Symbols::PrependTypeArguments()));
ASSERT(!prepend_function.IsNull());
body += StaticCall(TokenPosition::kNoSource, prepend_function, 3,
ICData::kStatic);
body += StoreLocal(TokenPosition::kNoSource, fn_type_args);
body += Drop();
} else {
body += LoadLocal(closure);
body += LoadField(Closure::function_type_arguments_offset());
body += StoreLocal(TokenPosition::kNoSource, fn_type_args);
body += Drop();
}
}
if (dart_function.IsConvertedClosureFunction()) {
body += LoadLocal(closure);
body += LoadField(Closure::context_offset());
LocalVariable* context = closure;
body += StoreLocal(TokenPosition::kNoSource, context);
// TODO(30455): Kernel generic methods undone. When generic closures are
// supported, the type arguments passed by the caller will actually need to
// be used here.
if (dart_function.IsGeneric() && I->reify_generic_functions()) {
LocalVariable* type_args_slot =
parsed_function()->function_type_arguments();
ASSERT(type_args_slot != NULL);
body += LoadField(Context::variable_offset(0));
body += StoreLocal(TokenPosition::kNoSource, type_args_slot);
}
body += Drop();
} else if (dart_function.IsClosureFunction() && dart_function.IsGeneric() &&
dart_function.NumParentTypeParameters() > 0 &&
I->reify_generic_functions()) {
LocalVariable* closure =
parsed_function()->node_sequence()->scope()->VariableAt(0);
LocalVariable* fn_type_args = parsed_function()->function_type_arguments();
ASSERT(fn_type_args != NULL && closure != NULL);
body += LoadLocal(fn_type_args);
body += PushArgument();
body += LoadLocal(closure);
body += LoadField(Closure::function_type_arguments_offset());
body += PushArgument();
body += IntConstant(dart_function.NumTypeParameters() +
dart_function.NumParentTypeParameters());
body += PushArgument();
const Library& dart_internal =
Library::Handle(Z, Library::InternalLibrary());
const Function& prepend_function =
Function::ZoneHandle(Z, dart_internal.LookupFunctionAllowPrivate(
Symbols::PrependTypeArguments()));
ASSERT(!prepend_function.IsNull());
body += StaticCall(TokenPosition::kNoSource, prepend_function, 3,
ICData::kStatic);
body += StoreLocal(TokenPosition::kNoSource, fn_type_args);
body += Drop();
}
@ -8370,7 +8374,15 @@ Fragment StreamingFlowGraphBuilder::BuildClosureCreation(
ReadCanonicalNameReference(); // read function reference.
Function& function = Function::ZoneHandle(
Z, H.LookupStaticMethodByKernelProcedure(function_reference));
function = function.ConvertedClosureFunction();
intptr_t num_type_parameters;
{
AlternativeReadingScope _(&reader_);
SkipExpression(); // context vector
SkipDartType(); // skip function type
num_type_parameters = ReadListLength();
}
function = function.ConvertedClosureFunction(num_type_parameters);
ASSERT(!function.IsNull());
const Class& closure_class =
@ -8391,34 +8403,25 @@ Fragment StreamingFlowGraphBuilder::BuildClosureCreation(
instructions +=
StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset());
SkipDartType(); // skip function type of the closure.
// TODO(30455): Kernel generic methods undone. When generic methods are
// fully supported in kernel, we'll need to store a NULL in the type arguments
// slot when type arguments are absent, so the wrapper for the target function
// can tell how many type args are captured vs. provided by the caller of the
// closure.
intptr_t types_count = ReadListLength(); // read type count.
if (types_count > 0) {
const TypeArguments& type_args =
T.BuildTypeArguments(types_count); // read list of type arguments.
instructions += TranslateInstantiatedTypeArguments(type_args);
LocalVariable* type_args_slot = MakeTemporary();
instructions += LoadLocal(context);
instructions += LoadLocal(type_args_slot);
instructions += StoreInstanceField(TokenPosition::kNoSource,
Context::variable_offset(0));
// Skip the function type of the closure (it's predicable from the
// target and the supplied type arguments).
SkipDartType();
ReadListLength(); // type parameter count
if (num_type_parameters > 0) {
instructions += LoadLocal(closure);
instructions += LoadLocal(type_args_slot);
const TypeArguments& type_args = T.BuildTypeArguments(
num_type_parameters); // read list of type arguments.
instructions += TranslateInstantiatedTypeArguments(type_args);
instructions += StoreInstanceField(
TokenPosition::kNoSource, Closure::function_type_arguments_offset());
instructions += Drop(); // type args
}
instructions += LoadLocal(closure);
instructions += Constant(Object::empty_type_arguments());
instructions += StoreInstanceField(TokenPosition::kNoSource,
Closure::delayed_type_arguments_offset());
instructions += Drop(); // context
return instructions;
}

View file

@ -1010,17 +1010,9 @@ Fragment FlowGraphBuilder::LoadFunctionTypeArguments() {
const Function& function = parsed_function_->function();
if (function.IsClosureFunction() && !function.IsGeneric()) {
LocalScope* scope = parsed_function_->node_sequence()->scope();
LocalVariable* closure = scope->VariableAt(0);
ASSERT(closure != NULL);
instructions += LoadLocal(closure);
instructions += LoadField(Closure::function_type_arguments_offset());
} else if (function.IsGeneric()) {
if (function.IsGeneric() || function.HasGenericParent()) {
ASSERT(parsed_function_->function_type_arguments() != NULL);
instructions += LoadLocal(parsed_function_->function_type_arguments());
} else {
instructions += NullConstant();
}

View file

@ -5845,6 +5845,8 @@ bool Function::HasGenericParent() const {
// The parent function of an implicit closure function is not the enclosing
// function we are asking about here.
return false;
} else if (IsConvertedClosureFunction()) {
return NumParentTypeParameters() > 0;
}
Function& parent = Function::Handle(parent_function());
while (!parent.IsNull()) {
@ -6252,6 +6254,8 @@ intptr_t Function::NumTypeParameters(Thread* thread) const {
intptr_t Function::NumParentTypeParameters() const {
if (IsImplicitClosureFunction()) {
return 0;
} else if (IsConvertedClosureFunction()) {
return num_parent_type_parameters();
}
Thread* thread = Thread::Current();
Function& parent = Function::Handle(parent_function());
@ -6778,21 +6782,10 @@ RawFunction* Function::InstantiateSignatureFrom(
}
}
Function& sig = Function::Handle(zone, Function::null());
if (IsConvertedClosureFunction() && !delete_type_parameters) {
sig = Function::NewConvertedClosureFunction(
String::Handle(zone, name()), parent, TokenPosition::kNoSource);
// TODO(30455): Kernel generic methods undone. Handle type parameters
// correctly when generic closures are supported. Until then, all type
// parameters to this target are used for captured type variables, so they
// aren't relevant to the type of the function.
sig.set_type_parameters(TypeArguments::Handle(zone, TypeArguments::null()));
} else {
sig = Function::NewSignatureFunction(owner, parent,
TokenPosition::kNoSource, space);
if (!delete_type_parameters) {
sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters()));
}
Function& sig = Function::Handle(Function::NewSignatureFunction(
owner, parent, TokenPosition::kNoSource, space));
if (!delete_type_parameters) {
sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters()));
}
AbstractType& type = AbstractType::Handle(zone, result_type());
@ -7465,7 +7458,8 @@ void Function::DropUncompiledImplicitClosureFunction() const {
//
// Function::ConvertedClosureFunction method follows the logic of
// Function::ImplicitClosureFunction method.
RawFunction* Function::ConvertedClosureFunction() const {
RawFunction* Function::ConvertedClosureFunction(
intptr_t num_parent_type_parameters) const {
// Return the existing converted closure function if any.
if (converted_closure_function() != Function::null()) {
return converted_closure_function();
@ -7483,8 +7477,28 @@ RawFunction* Function::ConvertedClosureFunction() const {
closure_function.set_context_scope(Object::empty_context_scope());
// Set closure function's type parameters.
closure_function.set_type_parameters(
TypeArguments::Handle(zone, type_parameters()));
{
TypeArguments& total_type_parameters =
TypeArguments::Handle(type_parameters());
intptr_t num_type_parameters =
total_type_parameters.Length() - num_parent_type_parameters;
if (num_type_parameters == 0) {
closure_function.set_type_parameters(Object::null_type_arguments());
} else {
ASSERT(num_type_parameters > 0);
TypeArguments& new_type_parameters =
TypeArguments::Handle(TypeArguments::New(num_type_parameters));
for (intptr_t i = 0; i < num_type_parameters; ++i) {
new_type_parameters.SetTypeAt(
i, AbstractType::Handle(total_type_parameters.TypeAt(
i + num_parent_type_parameters)));
}
closure_function.set_type_parameters(new_type_parameters);
}
closure_function.set_num_parent_type_parameters(num_parent_type_parameters);
}
// Set closure function's result type to this result type.
closure_function.set_result_type(AbstractType::Handle(zone, result_type()));
@ -7547,6 +7561,26 @@ void Function::DropUncompiledConvertedClosureFunction() const {
}
}
void Function::set_num_parent_type_parameters(intptr_t num) const {
if (IsConvertedClosureFunction()) {
const Object& obj = Object::Handle(raw_ptr()->data_);
ASSERT(!obj.IsNull());
ClosureData::Cast(obj).set_num_parent_type_parameters(num);
return;
}
UNREACHABLE();
}
intptr_t Function::num_parent_type_parameters() const {
if (IsConvertedClosureFunction()) {
const Object& obj = Object::Handle(raw_ptr()->data_);
ASSERT(!obj.IsNull());
return ClosureData::Cast(obj).num_parent_type_parameters();
}
UNREACHABLE();
return 0;
}
void Function::BuildSignatureParameters(
Thread* thread,
Zone* zone,
@ -7685,35 +7719,6 @@ RawString* Function::BuildSignature(NameVisibility name_visibility) const {
bool Function::HasInstantiatedSignature(Genericity genericity,
intptr_t num_free_fun_type_params,
TrailPtr trail) const {
// This function works differently for converted closures.
//
// Unlike regular closures, it's not possible to know which type parameters
// are supposed to come from parent functions or classes and which are
// actually parameters to the closure it represents. For example, consider:
//
// class C<T> {
// getf() => (T x) { return x; }
// }
//
// class D {
// getf() {
// dynamic fn<T>(T x) { return x; }
// return fn;
// }
// }
//
// The signature of `fn` as a converted closure will in both cases look like
// `<T>(T) => dynamic`, because the signature of the converted closure
// function is the same as its top-level target function. However, in the
// first case the closure's type is instantiated, and in the second case
// it's not.
//
// Since we can never assume a converted closure is instantiated if it has any
// type parameters, we always return true in these cases.
if (IsConvertedClosureFunction()) {
return genericity == kCurrentClass || NumTypeParameters() == 0;
}
if (num_free_fun_type_params == kCurrentAndEnclosingFree) {
num_free_fun_type_params = kAllFree;
} else if (genericity != kCurrentClass) {
@ -8113,6 +8118,14 @@ const char* Function::ToCString() const {
const_str);
}
intptr_t ClosureData::num_parent_type_parameters() const {
return Smi::Value(raw_ptr()->num_parent_type_parameters_);
}
void ClosureData::set_num_parent_type_parameters(intptr_t value) const {
StorePointer(&raw_ptr()->num_parent_type_parameters_, Smi::New(value));
}
void ClosureData::set_context_scope(const ContextScope& value) const {
StorePointer(&raw_ptr()->context_scope_, value.raw());
}

View file

@ -2168,6 +2168,11 @@ class Function : public Object {
RawArray* parameter_names() const { return raw_ptr()->parameter_names_; }
void set_parameter_names(const Array& value) const;
// For converted closure functions: indicate how many type parameters on the
// target are actually captured.
void set_num_parent_type_parameters(intptr_t num) const;
intptr_t num_parent_type_parameters() const;
// The type parameters (and their bounds) are specified as an array of
// TypeParameter.
RawTypeArguments* type_parameters() const {
@ -2305,7 +2310,8 @@ class Function : public Object {
// If none exists yet, create one and remember it. See the comment on
// ConvertedClosureFunction definition in runtime/vm/object.cc for elaborate
// explanation.
RawFunction* ConvertedClosureFunction() const;
RawFunction* ConvertedClosureFunction(
intptr_t num_parent_type_parameters) const;
void DropUncompiledConvertedClosureFunction() const;
// Return the closure implicitly created for this function.
@ -2988,6 +2994,9 @@ class ClosureData : public Object {
RawInstance* implicit_static_closure() const { return raw_ptr()->closure_; }
void set_implicit_static_closure(const Instance& closure) const;
intptr_t num_parent_type_parameters() const;
void set_num_parent_type_parameters(intptr_t value) const;
static RawClosureData* New();
FINAL_HEAP_OBJECT_IMPLEMENTATION(ClosureData, Object);

View file

@ -983,7 +983,8 @@ class RawClosureData : public RawObject {
RawFunction* parent_function_; // Enclosing function of this local function.
RawType* signature_type_;
RawInstance* closure_; // Closure object for static implicit closures.
VISIT_TO(RawObject*, closure_);
RawSmi* num_parent_type_parameters_; // For converted closures only
VISIT_TO(RawObject*, num_parent_type_parameters_);
friend class Function;
};

View file

@ -643,7 +643,8 @@ void LocalScope::CaptureLocalVariables(LocalScope* top_scope) {
(variable->name().raw() == Symbols::StackTraceVar().raw()) ||
(variable->name().raw() == Symbols::ExceptionVar().raw()) ||
(variable->name().raw() == Symbols::SavedTryContextVar().raw()) ||
(variable->name().raw() == Symbols::ArgDescVar().raw())) {
(variable->name().raw() == Symbols::ArgDescVar().raw()) ||
(variable->name().raw() == Symbols::FunctionTypeArgumentsVar().raw())) {
// Don't capture those variables because the VM expects them to be on
// the stack.
continue;