OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 12648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12659 | 12659 |
12660 // static | 12660 // static |
12661 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, | 12661 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, |
12662 Handle<JSFunction> constructor, | 12662 Handle<JSFunction> constructor, |
12663 Handle<JSReceiver> new_target) { | 12663 Handle<JSReceiver> new_target) { |
12664 EnsureHasInitialMap(constructor); | 12664 EnsureHasInitialMap(constructor); |
12665 | 12665 |
12666 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate); | 12666 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate); |
12667 if (*new_target == *constructor) return constructor_initial_map; | 12667 if (*new_target == *constructor) return constructor_initial_map; |
12668 | 12668 |
| 12669 // Fast case, new.target is a subclass of constructor. The map is cacheable |
| 12670 // (and may already have been cached). new.target.prototype is guaranteed to |
| 12671 // be a JSReceiver. |
| 12672 if (new_target->IsJSFunction()) { |
| 12673 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); |
| 12674 |
| 12675 // Check that |function|'s initial map still in sync with the |constructor|, |
| 12676 // otherwise we must create a new initial map for |function|. |
| 12677 if (function->has_initial_map() && |
| 12678 function->initial_map()->GetConstructor() == *constructor) { |
| 12679 return handle(function->initial_map(), isolate); |
| 12680 } |
| 12681 |
| 12682 // Create a new map with the size and number of in-object properties |
| 12683 // suggested by |function|. |
| 12684 |
| 12685 // Link initial map and constructor function if the new.target is actually a |
| 12686 // subclass constructor. |
| 12687 if (IsSubclassConstructor(function->shared()->kind())) { |
| 12688 Handle<Object> prototype(function->instance_prototype(), isolate); |
| 12689 InstanceType instance_type = constructor_initial_map->instance_type(); |
| 12690 DCHECK(CanSubclassHaveInobjectProperties(instance_type)); |
| 12691 int internal_fields = |
| 12692 JSObject::GetInternalFieldCount(*constructor_initial_map); |
| 12693 int pre_allocated = constructor_initial_map->GetInObjectProperties() - |
| 12694 constructor_initial_map->unused_property_fields(); |
| 12695 int instance_size; |
| 12696 int in_object_properties; |
| 12697 function->CalculateInstanceSizeForDerivedClass( |
| 12698 instance_type, internal_fields, &instance_size, |
| 12699 &in_object_properties); |
| 12700 |
| 12701 int unused_property_fields = in_object_properties - pre_allocated; |
| 12702 Handle<Map> map = |
| 12703 Map::CopyInitialMap(constructor_initial_map, instance_size, |
| 12704 in_object_properties, unused_property_fields); |
| 12705 map->set_new_target_is_base(false); |
| 12706 |
| 12707 JSFunction::SetInitialMap(function, map, prototype); |
| 12708 map->SetConstructor(*constructor); |
| 12709 map->StartInobjectSlackTracking(); |
| 12710 return map; |
| 12711 } |
| 12712 } |
| 12713 |
| 12714 // Slow path, new.target is either a proxy or can't cache the map. |
| 12715 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to |
| 12716 // fall back to the intrinsicDefaultProto. |
| 12717 Handle<Object> prototype; |
12669 if (new_target->IsJSProxy()) { | 12718 if (new_target->IsJSProxy()) { |
12670 Handle<JSProxy> new_target_proxy = Handle<JSProxy>::cast(new_target); | 12719 Handle<JSProxy> new_target_proxy = Handle<JSProxy>::cast(new_target); |
12671 Handle<Object> prototype; | |
12672 Handle<String> prototype_string = isolate->factory()->prototype_string(); | 12720 Handle<String> prototype_string = isolate->factory()->prototype_string(); |
12673 ASSIGN_RETURN_ON_EXCEPTION( | 12721 ASSIGN_RETURN_ON_EXCEPTION( |
12674 isolate, prototype, | 12722 isolate, prototype, |
12675 JSReceiver::GetProperty(new_target_proxy, prototype_string), Map); | 12723 JSReceiver::GetProperty(new_target_proxy, prototype_string), Map); |
12676 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); | 12724 } else { |
12677 map->set_new_target_is_base(false); | 12725 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); |
12678 | 12726 // Make sure the new.target.prototype is cached. |
12679 if (!prototype->IsJSReceiver()) { | 12727 EnsureHasInitialMap(function); |
12680 Handle<Context> context; | 12728 prototype = handle(function->prototype(), isolate); |
12681 ASSIGN_RETURN_ON_EXCEPTION( | |
12682 isolate, context, JSProxy::GetFunctionRealm(new_target_proxy), Map); | |
12683 DCHECK(context->IsNativeContext()); | |
12684 // TODO(verwaest): Use the intrinsicDefaultProto instead. | |
12685 prototype = handle(context->initial_object_prototype(), isolate); | |
12686 } | |
12687 | |
12688 if (map->prototype() != *prototype) { | |
12689 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); | |
12690 } | |
12691 | |
12692 map->SetConstructor(*constructor); | |
12693 return map; | |
12694 } | 12729 } |
12695 | 12730 |
12696 Handle<JSFunction> new_target_function = Handle<JSFunction>::cast(new_target); | 12731 if (!prototype->IsJSReceiver()) { |
12697 | 12732 Handle<Context> context; |
12698 // Check that |new_target_function|'s initial map still in sync with | 12733 ASSIGN_RETURN_ON_EXCEPTION(isolate, context, |
12699 // the |constructor|, otherwise we must create a new initial map for | 12734 JSReceiver::GetFunctionRealm(new_target), Map); |
12700 // |new_target_function|. | 12735 DCHECK(context->IsNativeContext()); |
12701 if (new_target_function->has_initial_map() && | 12736 // TODO(verwaest): Use the intrinsicDefaultProto instead. |
12702 new_target_function->initial_map()->GetConstructor() == *constructor) { | 12737 prototype = handle(context->initial_object_prototype(), isolate); |
12703 return handle(new_target_function->initial_map(), isolate); | |
12704 } | |
12705 | |
12706 // Create a new map with the size and number of in-object properties suggested | |
12707 // by the function. | |
12708 | |
12709 // Link initial map and constructor function if the original constructor is | |
12710 // actually a subclass constructor. | |
12711 if (IsSubclassConstructor(new_target_function->shared()->kind())) { | |
12712 Handle<Object> prototype(new_target_function->instance_prototype(), | |
12713 isolate); | |
12714 InstanceType instance_type = constructor_initial_map->instance_type(); | |
12715 DCHECK(CanSubclassHaveInobjectProperties(instance_type)); | |
12716 int internal_fields = | |
12717 JSObject::GetInternalFieldCount(*constructor_initial_map); | |
12718 int pre_allocated = constructor_initial_map->GetInObjectProperties() - | |
12719 constructor_initial_map->unused_property_fields(); | |
12720 int instance_size; | |
12721 int in_object_properties; | |
12722 new_target_function->CalculateInstanceSizeForDerivedClass( | |
12723 instance_type, internal_fields, &instance_size, &in_object_properties); | |
12724 | |
12725 int unused_property_fields = in_object_properties - pre_allocated; | |
12726 Handle<Map> map = | |
12727 Map::CopyInitialMap(constructor_initial_map, instance_size, | |
12728 in_object_properties, unused_property_fields); | |
12729 map->set_new_target_is_base(false); | |
12730 | |
12731 JSFunction::SetInitialMap(new_target_function, map, prototype); | |
12732 map->SetConstructor(*constructor); | |
12733 map->StartInobjectSlackTracking(); | |
12734 return map; | |
12735 } | |
12736 | |
12737 // Fetch the prototype. | |
12738 Handle<Object> prototype; | |
12739 if (new_target_function->map()->has_non_instance_prototype()) { | |
12740 // TODO(verwaest): In case of non-instance prototype, use the | |
12741 // intrinsicDefaultProto instead. | |
12742 prototype = handle(new_target_function->context() | |
12743 ->native_context() | |
12744 ->initial_object_prototype()); | |
12745 } else { | |
12746 // Make sure the prototype is cached on new_target_function. | |
12747 EnsureHasInitialMap(new_target_function); | |
12748 prototype = handle(new_target_function->instance_prototype(), isolate); | |
12749 } | 12738 } |
12750 | 12739 |
12751 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); | 12740 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); |
12752 map->set_new_target_is_base(false); | 12741 map->set_new_target_is_base(false); |
12753 DCHECK(prototype->IsJSReceiver()); | 12742 DCHECK(prototype->IsJSReceiver()); |
12754 if (map->prototype() != *prototype) { | 12743 if (map->prototype() != *prototype) { |
12755 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); | 12744 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); |
12756 } | 12745 } |
12757 map->SetConstructor(*constructor); | 12746 map->SetConstructor(*constructor); |
12758 return map; | 12747 return map; |
(...skipping 6422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19181 if (cell->value() != *new_value) { | 19170 if (cell->value() != *new_value) { |
19182 cell->set_value(*new_value); | 19171 cell->set_value(*new_value); |
19183 Isolate* isolate = cell->GetIsolate(); | 19172 Isolate* isolate = cell->GetIsolate(); |
19184 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 19173 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
19185 isolate, DependentCode::kPropertyCellChangedGroup); | 19174 isolate, DependentCode::kPropertyCellChangedGroup); |
19186 } | 19175 } |
19187 } | 19176 } |
19188 | 19177 |
19189 } // namespace internal | 19178 } // namespace internal |
19190 } // namespace v8 | 19179 } // namespace v8 |
OLD | NEW |