Index: src/builtins/builtins-constructor.cc |
diff --git a/src/builtins/builtins-constructor.cc b/src/builtins/builtins-constructor.cc |
index d7bf3cccdae3183cc55f26d59b731e57f0242a72..4ff9cd132cabe9468cfb25d78c4929750860bf8f 100644 |
--- a/src/builtins/builtins-constructor.cc |
+++ b/src/builtins/builtins-constructor.cc |
@@ -154,5 +154,119 @@ TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) { |
Return(EmitFastNewClosure(shared, context)); |
} |
+TF_BUILTIN(FastNewObject, ConstructorBuiltinsAssembler) { |
+ typedef FastNewObjectDescriptor Descriptor; |
+ Node* context = Parameter(Descriptor::kContext); |
+ Node* target = Parameter(Descriptor::kTarget); |
+ Node* new_target = Parameter(Descriptor::kNewTarget); |
+ |
+ CSA_ASSERT(this, HasInstanceType(target, JS_FUNCTION_TYPE)); |
+ CSA_ASSERT(this, IsJSReceiver(new_target)); |
+ |
+ // Verify that the new target is a JSFunction. |
+ Label runtime(this), fast(this); |
+ GotoIf(HasInstanceType(new_target, JS_FUNCTION_TYPE), &fast); |
+ Goto(&runtime); |
+ |
+ Bind(&runtime); |
+ TailCallRuntime(Runtime::kNewObject, context, target, new_target); |
+ |
+ Bind(&fast); |
+ |
+ // Load the initial map and verify that it's in fact a map. |
+ Node* initial_map = |
+ LoadObjectField(new_target, JSFunction::kPrototypeOrInitialMapOffset); |
+ GotoIf(TaggedIsSmi(initial_map), &runtime); |
+ GotoIf(DoesntHaveInstanceType(initial_map, MAP_TYPE), &runtime); |
+ |
+ // Fall back to runtime if the target differs from the new target's |
+ // initial map constructor. |
+ Node* new_target_constructor = |
+ LoadObjectField(initial_map, Map::kConstructorOrBackPointerOffset); |
+ GotoIf(WordNotEqual(target, new_target_constructor), &runtime); |
+ |
+ Node* instance_size_words = ChangeUint32ToWord(LoadObjectField( |
+ initial_map, Map::kInstanceSizeOffset, MachineType::Uint8())); |
+ Node* instance_size = |
+ WordShl(instance_size_words, IntPtrConstant(kPointerSizeLog2)); |
+ |
+ Node* object = Allocate(instance_size); |
+ StoreMapNoWriteBarrier(object, initial_map); |
+ Node* empty_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex); |
+ StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOffset, |
+ empty_array); |
+ StoreObjectFieldNoWriteBarrier(object, JSObject::kElementsOffset, |
+ empty_array); |
+ |
+ instance_size_words = ChangeUint32ToWord(LoadObjectField( |
+ initial_map, Map::kInstanceSizeOffset, MachineType::Uint8())); |
+ instance_size = |
+ WordShl(instance_size_words, IntPtrConstant(kPointerSizeLog2)); |
+ |
+ // Perform in-object slack tracking if requested. |
+ Node* bit_field3 = LoadMapBitField3(initial_map); |
+ Label slack_tracking(this), finalize(this, Label::kDeferred), done(this); |
+ GotoIf(IsSetWord32<Map::ConstructionCounter>(bit_field3), &slack_tracking); |
+ |
+ // Initialize remaining fields. |
+ { |
+ Comment("no slack tracking"); |
+ InitializeFieldsWithRoot(object, IntPtrConstant(JSObject::kHeaderSize), |
+ instance_size, Heap::kUndefinedValueRootIndex); |
+ Return(object); |
+ } |
+ |
+ { |
+ Bind(&slack_tracking); |
+ |
+ // Decrease generous allocation count. |
+ STATIC_ASSERT(Map::ConstructionCounter::kNext == 32); |
+ Comment("update allocation count"); |
+ Node* new_bit_field3 = Int32Sub( |
+ bit_field3, Int32Constant(1 << Map::ConstructionCounter::kShift)); |
+ StoreObjectFieldNoWriteBarrier(initial_map, Map::kBitField3Offset, |
+ new_bit_field3, |
+ MachineRepresentation::kWord32); |
+ GotoIf(IsClearWord32<Map::ConstructionCounter>(new_bit_field3), &finalize); |
+ |
+ Node* unused_fields = LoadObjectField( |
+ initial_map, Map::kUnusedPropertyFieldsOffset, MachineType::Uint8()); |
+ Node* used_size = |
+ IntPtrSub(instance_size, WordShl(ChangeUint32ToWord(unused_fields), |
+ IntPtrConstant(kPointerSizeLog2))); |
+ |
+ Comment("initialize filler fields (no finalize)"); |
+ InitializeFieldsWithRoot(object, used_size, instance_size, |
+ Heap::kOnePointerFillerMapRootIndex); |
+ |
+ Comment("initialize undefined fields (no finalize)"); |
+ InitializeFieldsWithRoot(object, IntPtrConstant(JSObject::kHeaderSize), |
+ used_size, Heap::kUndefinedValueRootIndex); |
+ Return(object); |
+ } |
+ |
+ { |
+ // Finalize the instance size. |
+ Bind(&finalize); |
+ |
+ Node* unused_fields = LoadObjectField( |
+ initial_map, Map::kUnusedPropertyFieldsOffset, MachineType::Uint8()); |
+ Node* used_size = |
+ IntPtrSub(instance_size, WordShl(ChangeUint32ToWord(unused_fields), |
+ IntPtrConstant(kPointerSizeLog2))); |
+ |
+ Comment("initialize filler fields (finalize)"); |
+ InitializeFieldsWithRoot(object, used_size, instance_size, |
+ Heap::kOnePointerFillerMapRootIndex); |
+ |
+ Comment("initialize undefined fields (finalize)"); |
+ InitializeFieldsWithRoot(object, IntPtrConstant(JSObject::kHeaderSize), |
+ used_size, Heap::kUndefinedValueRootIndex); |
+ |
+ CallRuntime(Runtime::kFinalizeInstanceSize, context, initial_map); |
+ Return(object); |
+ } |
+} |
+ |
} // namespace internal |
} // namespace v8 |