mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:09:49 +00:00
[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:
parent
6a8cad4877
commit
7e64ddd00f
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue