| 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
|
|
|