Chromium Code Reviews| 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)); |