Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index f1dd4d7efe96b236d1536c0611969bf3c1fa3de4..43ed55dc0d073aec3a558b0ff2e51b2607e6d088 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -12206,6 +12206,10 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { |
if (function->has_initial_map()) return; |
Isolate* isolate = function->GetIsolate(); |
+ // The constructor should be compiled for the optimization hints to be |
+ // available. |
+ Compiler::Compile(function, CLEAR_EXCEPTION); |
+ |
// First create a new map with the size and number of in-object properties |
// suggested by the function. |
InstanceType instance_type; |
@@ -12245,39 +12249,59 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { |
} |
-Handle<Map> JSFunction::EnsureDerivedHasInitialMap( |
- Handle<JSFunction> new_target, Handle<JSFunction> constructor) { |
- DCHECK(constructor->has_initial_map()); |
- Isolate* isolate = constructor->GetIsolate(); |
+// static |
+MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, |
+ Handle<JSFunction> constructor, |
+ Handle<JSReceiver> new_target) { |
+ EnsureHasInitialMap(constructor); |
+ |
Handle<Map> constructor_initial_map(constructor->initial_map(), isolate); |
if (*new_target == *constructor) return constructor_initial_map; |
- if (new_target->has_initial_map()) { |
- // Check that |new_target|'s initial map still in sync with |
- // the |constructor|, otherwise we must create a new initial map for |
- // |new_target|. |
- if (new_target->initial_map()->GetConstructor() == *constructor) { |
- return handle(new_target->initial_map(), isolate); |
+ |
+ if (new_target->IsJSProxy()) { |
+ Handle<JSProxy> new_target_proxy = Handle<JSProxy>::cast(new_target); |
+ Handle<Object> prototype; |
+ Handle<String> prototype_string = isolate->factory()->prototype_string(); |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, prototype, |
+ JSReceiver::GetProperty(new_target_proxy, prototype_string), Map); |
+ Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); |
+ |
+ if (!prototype->IsJSReceiver()) { |
+ Handle<Context> context; |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, context, JSProxy::GetFunctionRealm(new_target_proxy), Map); |
+ DCHECK(context->IsNativeContext()); |
+ // TODO(verwaest): Use the intrinsicDefaultProto instead. |
+ prototype = handle(context->initial_object_prototype(), isolate); |
+ } |
+ |
+ if (map->prototype() != *prototype) { |
+ Map::SetPrototype(map, prototype, FAST_PROTOTYPE); |
} |
+ |
+ map->SetConstructor(*constructor); |
+ return map; |
} |
- // First create a new map with the size and number of in-object properties |
- // suggested by the function. |
- DCHECK(!new_target->shared()->is_generator()); |
- DCHECK(!constructor->shared()->is_generator()); |
+ Handle<JSFunction> new_target_function = Handle<JSFunction>::cast(new_target); |
- // Fetch or allocate prototype. |
- // TODO(verwaest): In case of non-instance prototype, use the |
- // intrinsicDefaultProto instead. |
- Handle<Object> prototype; |
- if (new_target->has_instance_prototype()) { |
- prototype = handle(new_target->instance_prototype(), isolate); |
- } else { |
- prototype = isolate->factory()->NewFunctionPrototype(new_target); |
+ // Check that |new_target_function|'s initial map still in sync with |
+ // the |constructor|, otherwise we must create a new initial map for |
+ // |new_target_function|. |
+ if (new_target_function->has_initial_map() && |
+ new_target_function->initial_map()->GetConstructor() == *constructor) { |
+ return handle(new_target_function->initial_map(), isolate); |
} |
- // Finally link initial map and constructor function if the original |
- // constructor is actually a subclass constructor. |
- if (IsSubclassConstructor(new_target->shared()->kind())) { |
+ // Create a new map with the size and number of in-object properties suggested |
+ // by the function. |
+ |
+ // Link initial map and constructor function if the original constructor is |
+ // actually a subclass constructor. |
+ if (IsSubclassConstructor(new_target_function->shared()->kind())) { |
+ Handle<Object> prototype(new_target_function->instance_prototype(), |
+ isolate); |
InstanceType instance_type = constructor_initial_map->instance_type(); |
DCHECK(CanSubclassHaveInobjectProperties(instance_type)); |
int internal_fields = |
@@ -12286,7 +12310,7 @@ Handle<Map> JSFunction::EnsureDerivedHasInitialMap( |
constructor_initial_map->unused_property_fields(); |
int instance_size; |
int in_object_properties; |
- new_target->CalculateInstanceSizeForDerivedClass( |
+ new_target_function->CalculateInstanceSizeForDerivedClass( |
instance_type, internal_fields, &instance_size, &in_object_properties); |
int unused_property_fields = in_object_properties - pre_allocated; |
@@ -12294,20 +12318,33 @@ Handle<Map> JSFunction::EnsureDerivedHasInitialMap( |
Map::CopyInitialMap(constructor_initial_map, instance_size, |
in_object_properties, unused_property_fields); |
- JSFunction::SetInitialMap(new_target, map, prototype); |
+ JSFunction::SetInitialMap(new_target_function, map, prototype); |
map->SetConstructor(*constructor); |
- new_target->StartInobjectSlackTracking(); |
+ new_target_function->StartInobjectSlackTracking(); |
return map; |
+ } |
+ // Fetch the prototype. |
+ Handle<Object> prototype; |
+ if (new_target_function->map()->has_non_instance_prototype()) { |
+ // TODO(verwaest): In case of non-instance prototype, use the |
+ // intrinsicDefaultProto instead. |
+ prototype = handle(new_target_function->context() |
+ ->native_context() |
+ ->initial_object_prototype()); |
} else { |
- Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); |
- DCHECK(prototype->IsJSReceiver()); |
- if (map->prototype() != *prototype) { |
- Map::SetPrototype(map, prototype, FAST_PROTOTYPE); |
- } |
- map->SetConstructor(*constructor); |
- return map; |
+ // Make sure the prototype is cached on new_target_function. |
+ EnsureHasInitialMap(new_target_function); |
+ prototype = handle(new_target_function->instance_prototype(), isolate); |
} |
+ |
+ Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); |
+ DCHECK(prototype->IsJSReceiver()); |
+ if (map->prototype() != *prototype) { |
+ Map::SetPrototype(map, prototype, FAST_PROTOTYPE); |
+ } |
+ map->SetConstructor(*constructor); |
+ return map; |
} |