Index: src/builtins/builtins-internal.cc |
diff --git a/src/builtins/builtins-internal.cc b/src/builtins/builtins-internal.cc |
index f94ed0c16f2f6de091dfbd7da2f3077159fd3a89..984f964f84f5c879942edcd27390d957aebeb91a 100644 |
--- a/src/builtins/builtins-internal.cc |
+++ b/src/builtins/builtins-internal.cc |
@@ -309,6 +309,138 @@ void Builtins::Generate_NewRestParameterElements( |
assembler.Return(assembler.EmptyFixedArrayConstant()); |
} |
+void Builtins::Generate_FastNewObject(compiler::CodeAssemblerState* state) { |
mvstanton
2016/12/29 10:24:33
TF_BUILTIN is a nice helper if you like.
|
+ typedef CodeStubAssembler::Label Label; |
+ typedef compiler::Node Node; |
+ typedef FastNewObjectDescriptor Descriptor; |
+ CodeStubAssembler assembler(state); |
+ |
+ Node* context = assembler.Parameter(Descriptor::kContext); |
+ Node* target = assembler.Parameter(Descriptor::kTarget); |
+ Node* new_target = assembler.Parameter(Descriptor::kNewTarget); |
+ |
+ CSA_ASSERT(&assembler, assembler.HasInstanceType(target, JS_FUNCTION_TYPE)); |
+ CSA_ASSERT(&assembler, assembler.IsJSReceiver(new_target)); |
+ |
+ // Verify that the new target is a JSFunction. |
+ Label runtime(&assembler), fast(&assembler); |
+ assembler.GotoIf(assembler.HasInstanceType(new_target, JS_FUNCTION_TYPE), |
+ &fast); |
+ assembler.Goto(&runtime); |
+ |
+ assembler.Bind(&runtime); |
+ assembler.TailCallRuntime(Runtime::kNewObject, context, target, new_target); |
+ |
+ assembler.Bind(&fast); |
+ |
+ // Load the initial map and verify that it's in fact a map. |
+ Node* initial_map = assembler.LoadObjectField( |
+ new_target, JSFunction::kPrototypeOrInitialMapOffset); |
+ assembler.GotoIf(assembler.TaggedIsSmi(initial_map), &runtime); |
+ assembler.GotoIf(assembler.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 = assembler.LoadObjectField( |
+ initial_map, Map::kConstructorOrBackPointerOffset); |
+ assembler.GotoIf(assembler.WordNotEqual(target, new_target_constructor), |
+ &runtime); |
+ |
+ Node* instance_size_words = |
+ assembler.ChangeUint32ToWord(assembler.LoadObjectField( |
+ initial_map, Map::kInstanceSizeOffset, MachineType::Uint8())); |
+ Node* instance_size = assembler.WordShl( |
+ instance_size_words, assembler.IntPtrConstant(kPointerSizeLog2)); |
+ |
+ Node* object = assembler.Allocate(instance_size); |
+ assembler.StoreMapNoWriteBarrier(object, initial_map); |
+ Node* empty_array = assembler.LoadRoot(Heap::kEmptyFixedArrayRootIndex); |
+ assembler.StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOffset, |
+ empty_array); |
+ assembler.StoreObjectFieldNoWriteBarrier(object, JSObject::kElementsOffset, |
+ empty_array); |
+ |
+ instance_size_words = assembler.ChangeUint32ToWord(assembler.LoadObjectField( |
+ initial_map, Map::kInstanceSizeOffset, MachineType::Uint8())); |
+ instance_size = assembler.WordShl(instance_size_words, |
+ assembler.IntPtrConstant(kPointerSizeLog2)); |
+ |
+ // Perform in-object slack tracking if requested. |
+ Node* bit_field3 = assembler.LoadMapBitField3(initial_map); |
+ Label slack_tracking(&assembler), finalize(&assembler, Label::kDeferred), |
+ done(&assembler); |
+ assembler.GotoIf(assembler.IsSetWord32<Map::ConstructionCounter>(bit_field3), |
+ &slack_tracking); |
+ |
+ // Initialize remaining fields. |
+ { |
+ assembler.Comment("no slack tracking"); |
+ assembler.InitializeFieldsWithRoot( |
+ object, assembler.IntPtrConstant(JSObject::kHeaderSize), instance_size, |
+ Heap::kUndefinedValueRootIndex); |
+ assembler.Return(object); |
+ } |
+ |
+ { |
+ assembler.Bind(&slack_tracking); |
+ |
+ // Decrease generous allocation count. |
+ STATIC_ASSERT(Map::ConstructionCounter::kNext == 32); |
+ assembler.Comment("update allocation count"); |
+ Node* new_bit_field3 = assembler.Int32Sub( |
+ bit_field3, |
+ assembler.Int32Constant(1 << Map::ConstructionCounter::kShift)); |
+ assembler.StoreObjectFieldNoWriteBarrier(initial_map, Map::kBitField3Offset, |
+ new_bit_field3, |
+ MachineRepresentation::kWord32); |
+ assembler.GotoIf( |
+ assembler.IsClearWord32<Map::ConstructionCounter>(new_bit_field3), |
+ &finalize); |
+ |
+ Node* unused_fields = assembler.LoadObjectField( |
+ initial_map, Map::kUnusedPropertyFieldsOffset, MachineType::Uint8()); |
+ Node* used_size = assembler.IntPtrSub( |
+ instance_size, |
+ assembler.WordShl(assembler.ChangeUint32ToWord(unused_fields), |
+ assembler.IntPtrConstant(kPointerSizeLog2))); |
+ |
+ assembler.Comment("initialize filler fields (no finalize)"); |
+ assembler.InitializeFieldsWithRoot(object, used_size, instance_size, |
+ Heap::kOnePointerFillerMapRootIndex); |
+ |
+ assembler.Comment("initialize undefined fields (no finalize)"); |
+ assembler.InitializeFieldsWithRoot( |
+ object, assembler.IntPtrConstant(JSObject::kHeaderSize), used_size, |
+ Heap::kUndefinedValueRootIndex); |
+ assembler.Return(object); |
+ } |
+ |
+ { |
+ // Finalize the instance size. |
+ assembler.Bind(&finalize); |
+ |
+ Node* unused_fields = assembler.LoadObjectField( |
+ initial_map, Map::kUnusedPropertyFieldsOffset, MachineType::Uint8()); |
+ Node* used_size = assembler.IntPtrSub( |
+ instance_size, |
+ assembler.WordShl(assembler.ChangeUint32ToWord(unused_fields), |
+ assembler.IntPtrConstant(kPointerSizeLog2))); |
+ |
+ assembler.Comment("initialize filler fields (finalize)"); |
+ assembler.InitializeFieldsWithRoot(object, used_size, instance_size, |
+ Heap::kOnePointerFillerMapRootIndex); |
+ |
+ assembler.Comment("initialize undefined fields (finalize)"); |
+ assembler.InitializeFieldsWithRoot( |
+ object, assembler.IntPtrConstant(JSObject::kHeaderSize), used_size, |
+ Heap::kUndefinedValueRootIndex); |
+ |
+ assembler.CallRuntime(Runtime::kFinalizeInstanceSize, context, initial_map); |
+ assembler.Return(object); |
+ } |
+} |
+ |
void Builtins::Generate_ReturnReceiver(compiler::CodeAssemblerState* state) { |
CodeStubAssembler assembler(state); |
assembler.Return(assembler.Parameter(0)); |