Index: src/builtins/builtins-constructor.cc |
diff --git a/src/builtins/builtins-constructor.cc b/src/builtins/builtins-constructor.cc |
deleted file mode 100644 |
index 0d303c90c156b3dad8c11e8dc70469bfe49ea05a..0000000000000000000000000000000000000000 |
--- a/src/builtins/builtins-constructor.cc |
+++ /dev/null |
@@ -1,794 +0,0 @@ |
-// Copyright 2016 the V8 project authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "src/builtins/builtins-constructor.h" |
-#include "src/ast/ast.h" |
-#include "src/builtins/builtins-utils.h" |
-#include "src/builtins/builtins.h" |
-#include "src/code-factory.h" |
-#include "src/code-stub-assembler.h" |
-#include "src/counters.h" |
-#include "src/interface-descriptors.h" |
-#include "src/objects-inl.h" |
- |
-namespace v8 { |
-namespace internal { |
- |
-typedef compiler::Node Node; |
- |
-Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info, |
- Node* feedback_vector, |
- Node* slot, |
- Node* context) { |
- typedef compiler::CodeAssembler::Label Label; |
- typedef compiler::CodeAssembler::Variable Variable; |
- |
- Isolate* isolate = this->isolate(); |
- Factory* factory = isolate->factory(); |
- IncrementCounter(isolate->counters()->fast_new_closure_total(), 1); |
- |
- // Create a new closure from the given function info in new space |
- Node* result = Allocate(JSFunction::kSize); |
- |
- // Calculate the index of the map we should install on the function based on |
- // the FunctionKind and LanguageMode of the function. |
- // Note: Must be kept in sync with Context::FunctionMapIndex |
- Node* compiler_hints = |
- LoadObjectField(shared_info, SharedFunctionInfo::kCompilerHintsOffset, |
- MachineType::Uint32()); |
- Node* is_strict = Word32And( |
- compiler_hints, Int32Constant(1 << SharedFunctionInfo::kStrictModeBit)); |
- |
- Label if_normal(this), if_generator(this), if_async(this), |
- if_class_constructor(this), if_function_without_prototype(this), |
- load_map(this); |
- Variable map_index(this, MachineType::PointerRepresentation()); |
- |
- STATIC_ASSERT(FunctionKind::kNormalFunction == 0); |
- Node* is_not_normal = |
- Word32And(compiler_hints, |
- Int32Constant(SharedFunctionInfo::kAllFunctionKindBitsMask)); |
- GotoIfNot(is_not_normal, &if_normal); |
- |
- Node* is_generator = Word32And( |
- compiler_hints, Int32Constant(FunctionKind::kGeneratorFunction |
- << SharedFunctionInfo::kFunctionKindShift)); |
- GotoIf(is_generator, &if_generator); |
- |
- Node* is_async = Word32And( |
- compiler_hints, Int32Constant(FunctionKind::kAsyncFunction |
- << SharedFunctionInfo::kFunctionKindShift)); |
- GotoIf(is_async, &if_async); |
- |
- Node* is_class_constructor = Word32And( |
- compiler_hints, Int32Constant(FunctionKind::kClassConstructor |
- << SharedFunctionInfo::kFunctionKindShift)); |
- GotoIf(is_class_constructor, &if_class_constructor); |
- |
- if (FLAG_debug_code) { |
- // Function must be a function without a prototype. |
- CSA_ASSERT( |
- this, |
- Word32And(compiler_hints, |
- Int32Constant((FunctionKind::kAccessorFunction | |
- FunctionKind::kArrowFunction | |
- FunctionKind::kConciseMethod) |
- << SharedFunctionInfo::kFunctionKindShift))); |
- } |
- Goto(&if_function_without_prototype); |
- |
- Bind(&if_normal); |
- { |
- map_index.Bind(SelectIntPtrConstant(is_strict, |
- Context::STRICT_FUNCTION_MAP_INDEX, |
- Context::SLOPPY_FUNCTION_MAP_INDEX)); |
- Goto(&load_map); |
- } |
- |
- Bind(&if_generator); |
- { |
- map_index.Bind(IntPtrConstant(Context::GENERATOR_FUNCTION_MAP_INDEX)); |
- Goto(&load_map); |
- } |
- |
- Bind(&if_async); |
- { |
- map_index.Bind(IntPtrConstant(Context::ASYNC_FUNCTION_MAP_INDEX)); |
- Goto(&load_map); |
- } |
- |
- Bind(&if_class_constructor); |
- { |
- map_index.Bind(IntPtrConstant(Context::CLASS_FUNCTION_MAP_INDEX)); |
- Goto(&load_map); |
- } |
- |
- Bind(&if_function_without_prototype); |
- { |
- map_index.Bind( |
- IntPtrConstant(Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); |
- Goto(&load_map); |
- } |
- |
- Bind(&load_map); |
- |
- // Get the function map in the current native context and set that |
- // as the map of the allocated object. |
- Node* native_context = LoadNativeContext(context); |
- Node* map_slot_value = |
- LoadFixedArrayElement(native_context, map_index.value()); |
- StoreMapNoWriteBarrier(result, map_slot_value); |
- |
- // Initialize the rest of the function. |
- Node* empty_fixed_array = HeapConstant(factory->empty_fixed_array()); |
- StoreObjectFieldNoWriteBarrier(result, JSObject::kPropertiesOffset, |
- empty_fixed_array); |
- StoreObjectFieldNoWriteBarrier(result, JSObject::kElementsOffset, |
- empty_fixed_array); |
- Node* literals_cell = LoadFixedArrayElement( |
- feedback_vector, slot, 0, CodeStubAssembler::SMI_PARAMETERS); |
- { |
- // Bump the closure counter encoded in the cell's map. |
- Node* cell_map = LoadMap(literals_cell); |
- Label no_closures(this), one_closure(this), cell_done(this); |
- |
- GotoIf(IsNoClosuresCellMap(cell_map), &no_closures); |
- GotoIf(IsOneClosureCellMap(cell_map), &one_closure); |
- CSA_ASSERT(this, IsManyClosuresCellMap(cell_map)); |
- Goto(&cell_done); |
- |
- Bind(&no_closures); |
- StoreMapNoWriteBarrier(literals_cell, Heap::kOneClosureCellMapRootIndex); |
- Goto(&cell_done); |
- |
- Bind(&one_closure); |
- StoreMapNoWriteBarrier(literals_cell, Heap::kManyClosuresCellMapRootIndex); |
- Goto(&cell_done); |
- |
- Bind(&cell_done); |
- } |
- StoreObjectFieldNoWriteBarrier(result, JSFunction::kFeedbackVectorOffset, |
- literals_cell); |
- StoreObjectFieldNoWriteBarrier( |
- result, JSFunction::kPrototypeOrInitialMapOffset, TheHoleConstant()); |
- StoreObjectFieldNoWriteBarrier(result, JSFunction::kSharedFunctionInfoOffset, |
- shared_info); |
- StoreObjectFieldNoWriteBarrier(result, JSFunction::kContextOffset, context); |
- Handle<Code> lazy_builtin_handle( |
- isolate->builtins()->builtin(Builtins::kCompileLazy)); |
- Node* lazy_builtin = HeapConstant(lazy_builtin_handle); |
- Node* lazy_builtin_entry = |
- IntPtrAdd(BitcastTaggedToWord(lazy_builtin), |
- IntPtrConstant(Code::kHeaderSize - kHeapObjectTag)); |
- StoreObjectFieldNoWriteBarrier(result, JSFunction::kCodeEntryOffset, |
- lazy_builtin_entry, |
- MachineType::PointerRepresentation()); |
- StoreObjectFieldNoWriteBarrier(result, JSFunction::kNextFunctionLinkOffset, |
- UndefinedConstant()); |
- |
- return result; |
-} |
- |
-TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) { |
- Node* shared = Parameter(FastNewClosureDescriptor::kSharedFunctionInfo); |
- Node* context = Parameter(FastNewClosureDescriptor::kContext); |
- Node* vector = Parameter(FastNewClosureDescriptor::kVector); |
- Node* slot = Parameter(FastNewClosureDescriptor::kSlot); |
- Return(EmitFastNewClosure(shared, vector, slot, context)); |
-} |
- |
-TF_BUILTIN(FastNewObject, ConstructorBuiltinsAssembler) { |
- typedef FastNewObjectDescriptor Descriptor; |
- Node* context = Parameter(Descriptor::kContext); |
- Node* target = Parameter(Descriptor::kTarget); |
- Node* new_target = Parameter(Descriptor::kNewTarget); |
- |
- Label call_runtime(this); |
- |
- Node* result = EmitFastNewObject(context, target, new_target, &call_runtime); |
- Return(result); |
- |
- Bind(&call_runtime); |
- TailCallRuntime(Runtime::kNewObject, context, target, new_target); |
-} |
- |
-Node* ConstructorBuiltinsAssembler::EmitFastNewObject(Node* context, |
- Node* target, |
- Node* new_target) { |
- Variable var_obj(this, MachineRepresentation::kTagged); |
- Label call_runtime(this), end(this); |
- |
- Node* result = EmitFastNewObject(context, target, new_target, &call_runtime); |
- var_obj.Bind(result); |
- Goto(&end); |
- |
- Bind(&call_runtime); |
- var_obj.Bind(CallRuntime(Runtime::kNewObject, context, target, new_target)); |
- Goto(&end); |
- |
- Bind(&end); |
- return var_obj.value(); |
-} |
- |
-Node* ConstructorBuiltinsAssembler::EmitFastNewObject( |
- Node* context, Node* target, Node* new_target, |
- CodeAssemblerLabel* call_runtime) { |
- CSA_ASSERT(this, HasInstanceType(target, JS_FUNCTION_TYPE)); |
- CSA_ASSERT(this, IsJSReceiver(new_target)); |
- |
- // Verify that the new target is a JSFunction. |
- Label fast(this), end(this); |
- GotoIf(HasInstanceType(new_target, JS_FUNCTION_TYPE), &fast); |
- Goto(call_runtime); |
- |
- 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), call_runtime); |
- GotoIf(DoesntHaveInstanceType(initial_map, MAP_TYPE), call_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), call_runtime); |
- |
- Variable properties(this, MachineRepresentation::kTagged); |
- |
- Label instantiate_map(this), allocate_properties(this); |
- GotoIf(IsDictionaryMap(initial_map), &allocate_properties); |
- { |
- properties.Bind(EmptyFixedArrayConstant()); |
- Goto(&instantiate_map); |
- } |
- Bind(&allocate_properties); |
- { |
- properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity)); |
- Goto(&instantiate_map); |
- } |
- |
- Bind(&instantiate_map); |
- |
- Node* object = AllocateJSObjectFromMap(initial_map, properties.value()); |
- |
- Node* instance_size_words = ChangeUint32ToWord(LoadObjectField( |
- initial_map, Map::kInstanceSizeOffset, MachineType::Uint8())); |
- Node* 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); |
- Goto(&end); |
- } |
- |
- { |
- 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); |
- Goto(&end); |
- } |
- |
- { |
- // 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); |
- Goto(&end); |
- } |
- |
- Bind(&end); |
- return object; |
-} |
- |
-Node* ConstructorBuiltinsAssembler::EmitFastNewFunctionContext( |
- Node* function, Node* slots, Node* context, ScopeType scope_type) { |
- slots = ChangeUint32ToWord(slots); |
- |
- // TODO(ishell): Use CSA::OptimalParameterMode() here. |
- CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
- Node* min_context_slots = IntPtrConstant(Context::MIN_CONTEXT_SLOTS); |
- Node* length = IntPtrAdd(slots, min_context_slots); |
- Node* size = GetFixedArrayAllocationSize(length, FAST_ELEMENTS, mode); |
- |
- // Create a new closure from the given function info in new space |
- Node* function_context = AllocateInNewSpace(size); |
- |
- Heap::RootListIndex context_type; |
- switch (scope_type) { |
- case EVAL_SCOPE: |
- context_type = Heap::kEvalContextMapRootIndex; |
- break; |
- case FUNCTION_SCOPE: |
- context_type = Heap::kFunctionContextMapRootIndex; |
- break; |
- default: |
- UNREACHABLE(); |
- } |
- StoreMapNoWriteBarrier(function_context, context_type); |
- StoreObjectFieldNoWriteBarrier(function_context, Context::kLengthOffset, |
- SmiTag(length)); |
- |
- // Set up the fixed slots. |
- StoreFixedArrayElement(function_context, Context::CLOSURE_INDEX, function, |
- SKIP_WRITE_BARRIER); |
- StoreFixedArrayElement(function_context, Context::PREVIOUS_INDEX, context, |
- SKIP_WRITE_BARRIER); |
- StoreFixedArrayElement(function_context, Context::EXTENSION_INDEX, |
- TheHoleConstant(), SKIP_WRITE_BARRIER); |
- |
- // Copy the native context from the previous context. |
- Node* native_context = LoadNativeContext(context); |
- StoreFixedArrayElement(function_context, Context::NATIVE_CONTEXT_INDEX, |
- native_context, SKIP_WRITE_BARRIER); |
- |
- // Initialize the rest of the slots to undefined. |
- Node* undefined = UndefinedConstant(); |
- BuildFastFixedArrayForEach( |
- function_context, FAST_ELEMENTS, min_context_slots, length, |
- [this, undefined](Node* context, Node* offset) { |
- StoreNoWriteBarrier(MachineRepresentation::kTagged, context, offset, |
- undefined); |
- }, |
- mode); |
- |
- return function_context; |
-} |
- |
-// static |
-int ConstructorBuiltinsAssembler::MaximumFunctionContextSlots() { |
- return FLAG_test_small_max_function_context_stub_size ? kSmallMaximumSlots |
- : kMaximumSlots; |
-} |
- |
-TF_BUILTIN(FastNewFunctionContextEval, ConstructorBuiltinsAssembler) { |
- Node* function = Parameter(FastNewFunctionContextDescriptor::kFunction); |
- Node* slots = Parameter(FastNewFunctionContextDescriptor::kSlots); |
- Node* context = Parameter(FastNewFunctionContextDescriptor::kContext); |
- Return(EmitFastNewFunctionContext(function, slots, context, |
- ScopeType::EVAL_SCOPE)); |
-} |
- |
-TF_BUILTIN(FastNewFunctionContextFunction, ConstructorBuiltinsAssembler) { |
- Node* function = Parameter(FastNewFunctionContextDescriptor::kFunction); |
- Node* slots = Parameter(FastNewFunctionContextDescriptor::kSlots); |
- Node* context = Parameter(FastNewFunctionContextDescriptor::kContext); |
- Return(EmitFastNewFunctionContext(function, slots, context, |
- ScopeType::FUNCTION_SCOPE)); |
-} |
- |
-Handle<Code> Builtins::NewFunctionContext(ScopeType scope_type) { |
- switch (scope_type) { |
- case ScopeType::EVAL_SCOPE: |
- return FastNewFunctionContextEval(); |
- case ScopeType::FUNCTION_SCOPE: |
- return FastNewFunctionContextFunction(); |
- default: |
- UNREACHABLE(); |
- } |
- return Handle<Code>::null(); |
-} |
- |
-Node* ConstructorBuiltinsAssembler::EmitFastCloneRegExp(Node* closure, |
- Node* literal_index, |
- Node* pattern, |
- Node* flags, |
- Node* context) { |
- typedef CodeStubAssembler::Label Label; |
- typedef CodeStubAssembler::Variable Variable; |
- typedef compiler::Node Node; |
- |
- Label call_runtime(this, Label::kDeferred), end(this); |
- |
- Variable result(this, MachineRepresentation::kTagged); |
- |
- Node* cell = LoadObjectField(closure, JSFunction::kFeedbackVectorOffset); |
- Node* feedback_vector = LoadObjectField(cell, Cell::kValueOffset); |
- Node* boilerplate = LoadFixedArrayElement(feedback_vector, literal_index, 0, |
- CodeStubAssembler::SMI_PARAMETERS); |
- GotoIf(IsUndefined(boilerplate), &call_runtime); |
- |
- { |
- int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
- Node* copy = Allocate(size); |
- for (int offset = 0; offset < size; offset += kPointerSize) { |
- Node* value = LoadObjectField(boilerplate, offset); |
- StoreObjectFieldNoWriteBarrier(copy, offset, value); |
- } |
- result.Bind(copy); |
- Goto(&end); |
- } |
- |
- Bind(&call_runtime); |
- { |
- result.Bind(CallRuntime(Runtime::kCreateRegExpLiteral, context, closure, |
- literal_index, pattern, flags)); |
- Goto(&end); |
- } |
- |
- Bind(&end); |
- return result.value(); |
-} |
- |
-TF_BUILTIN(FastCloneRegExp, ConstructorBuiltinsAssembler) { |
- Node* closure = Parameter(FastCloneRegExpDescriptor::kClosure); |
- Node* literal_index = Parameter(FastCloneRegExpDescriptor::kLiteralIndex); |
- Node* pattern = Parameter(FastCloneRegExpDescriptor::kPattern); |
- Node* flags = Parameter(FastCloneRegExpDescriptor::kFlags); |
- Node* context = Parameter(FastCloneRegExpDescriptor::kContext); |
- |
- Return(EmitFastCloneRegExp(closure, literal_index, pattern, flags, context)); |
-} |
- |
-Node* ConstructorBuiltinsAssembler::NonEmptyShallowClone( |
- Node* boilerplate, Node* boilerplate_map, Node* boilerplate_elements, |
- Node* allocation_site, Node* capacity, ElementsKind kind) { |
- typedef CodeStubAssembler::ParameterMode ParameterMode; |
- |
- ParameterMode param_mode = OptimalParameterMode(); |
- |
- Node* length = LoadJSArrayLength(boilerplate); |
- capacity = TaggedToParameter(capacity, param_mode); |
- |
- Node *array, *elements; |
- std::tie(array, elements) = AllocateUninitializedJSArrayWithElements( |
- kind, boilerplate_map, length, allocation_site, capacity, param_mode); |
- |
- Comment("copy elements header"); |
- // Header consists of map and length. |
- STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize); |
- StoreMap(elements, LoadMap(boilerplate_elements)); |
- { |
- int offset = FixedArrayBase::kLengthOffset; |
- StoreObjectFieldNoWriteBarrier( |
- elements, offset, LoadObjectField(boilerplate_elements, offset)); |
- } |
- |
- length = TaggedToParameter(length, param_mode); |
- |
- Comment("copy boilerplate elements"); |
- CopyFixedArrayElements(kind, boilerplate_elements, elements, length, |
- SKIP_WRITE_BARRIER, param_mode); |
- IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); |
- |
- return array; |
-} |
- |
-Node* ConstructorBuiltinsAssembler::EmitFastCloneShallowArray( |
- Node* closure, Node* literal_index, Node* context, |
- CodeAssemblerLabel* call_runtime, AllocationSiteMode allocation_site_mode) { |
- typedef CodeStubAssembler::Label Label; |
- typedef CodeStubAssembler::Variable Variable; |
- typedef compiler::Node Node; |
- |
- Label zero_capacity(this), cow_elements(this), fast_elements(this), |
- return_result(this); |
- Variable result(this, MachineRepresentation::kTagged); |
- |
- Node* cell = LoadObjectField(closure, JSFunction::kFeedbackVectorOffset); |
- Node* feedback_vector = LoadObjectField(cell, Cell::kValueOffset); |
- Node* allocation_site = LoadFixedArrayElement( |
- feedback_vector, literal_index, 0, CodeStubAssembler::SMI_PARAMETERS); |
- |
- GotoIf(IsUndefined(allocation_site), call_runtime); |
- allocation_site = LoadFixedArrayElement(feedback_vector, literal_index, 0, |
- CodeStubAssembler::SMI_PARAMETERS); |
- |
- Node* boilerplate = |
- LoadObjectField(allocation_site, AllocationSite::kTransitionInfoOffset); |
- Node* boilerplate_map = LoadMap(boilerplate); |
- Node* boilerplate_elements = LoadElements(boilerplate); |
- Node* capacity = LoadFixedArrayBaseLength(boilerplate_elements); |
- allocation_site = |
- allocation_site_mode == TRACK_ALLOCATION_SITE ? allocation_site : nullptr; |
- |
- Node* zero = SmiConstant(Smi::kZero); |
- GotoIf(SmiEqual(capacity, zero), &zero_capacity); |
- |
- Node* elements_map = LoadMap(boilerplate_elements); |
- GotoIf(IsFixedCOWArrayMap(elements_map), &cow_elements); |
- |
- GotoIf(IsFixedArrayMap(elements_map), &fast_elements); |
- { |
- Comment("fast double elements path"); |
- if (FLAG_debug_code) { |
- Label correct_elements_map(this), abort(this, Label::kDeferred); |
- Branch(IsFixedDoubleArrayMap(elements_map), &correct_elements_map, |
- &abort); |
- |
- Bind(&abort); |
- { |
- Node* abort_id = SmiConstant( |
- Smi::FromInt(BailoutReason::kExpectedFixedDoubleArrayMap)); |
- CallRuntime(Runtime::kAbort, context, abort_id); |
- result.Bind(UndefinedConstant()); |
- Goto(&return_result); |
- } |
- Bind(&correct_elements_map); |
- } |
- |
- Node* array = |
- NonEmptyShallowClone(boilerplate, boilerplate_map, boilerplate_elements, |
- allocation_site, capacity, FAST_DOUBLE_ELEMENTS); |
- result.Bind(array); |
- Goto(&return_result); |
- } |
- |
- Bind(&fast_elements); |
- { |
- Comment("fast elements path"); |
- Node* array = |
- NonEmptyShallowClone(boilerplate, boilerplate_map, boilerplate_elements, |
- allocation_site, capacity, FAST_ELEMENTS); |
- result.Bind(array); |
- Goto(&return_result); |
- } |
- |
- Variable length(this, MachineRepresentation::kTagged), |
- elements(this, MachineRepresentation::kTagged); |
- Label allocate_without_elements(this); |
- |
- Bind(&cow_elements); |
- { |
- Comment("fixed cow path"); |
- length.Bind(LoadJSArrayLength(boilerplate)); |
- elements.Bind(boilerplate_elements); |
- |
- Goto(&allocate_without_elements); |
- } |
- |
- Bind(&zero_capacity); |
- { |
- Comment("zero capacity path"); |
- length.Bind(zero); |
- elements.Bind(LoadRoot(Heap::kEmptyFixedArrayRootIndex)); |
- |
- Goto(&allocate_without_elements); |
- } |
- |
- Bind(&allocate_without_elements); |
- { |
- Node* array = AllocateUninitializedJSArrayWithoutElements( |
- FAST_ELEMENTS, boilerplate_map, length.value(), allocation_site); |
- StoreObjectField(array, JSObject::kElementsOffset, elements.value()); |
- result.Bind(array); |
- Goto(&return_result); |
- } |
- |
- Bind(&return_result); |
- return result.value(); |
-} |
- |
-void ConstructorBuiltinsAssembler::CreateFastCloneShallowArrayBuiltin( |
- AllocationSiteMode allocation_site_mode) { |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- |
- Node* closure = Parameter(FastCloneShallowArrayDescriptor::kClosure); |
- Node* literal_index = |
- Parameter(FastCloneShallowArrayDescriptor::kLiteralIndex); |
- Node* constant_elements = |
- Parameter(FastCloneShallowArrayDescriptor::kConstantElements); |
- Node* context = Parameter(FastCloneShallowArrayDescriptor::kContext); |
- Label call_runtime(this, Label::kDeferred); |
- Return(EmitFastCloneShallowArray(closure, literal_index, context, |
- &call_runtime, allocation_site_mode)); |
- |
- Bind(&call_runtime); |
- { |
- Comment("call runtime"); |
- Node* flags = |
- SmiConstant(Smi::FromInt(ArrayLiteral::kShallowElements | |
- (allocation_site_mode == TRACK_ALLOCATION_SITE |
- ? 0 |
- : ArrayLiteral::kDisableMementos))); |
- Return(CallRuntime(Runtime::kCreateArrayLiteral, context, closure, |
- literal_index, constant_elements, flags)); |
- } |
-} |
- |
-TF_BUILTIN(FastCloneShallowArrayTrack, ConstructorBuiltinsAssembler) { |
- CreateFastCloneShallowArrayBuiltin(TRACK_ALLOCATION_SITE); |
-} |
- |
-TF_BUILTIN(FastCloneShallowArrayDontTrack, ConstructorBuiltinsAssembler) { |
- CreateFastCloneShallowArrayBuiltin(DONT_TRACK_ALLOCATION_SITE); |
-} |
- |
-Handle<Code> Builtins::NewCloneShallowArray( |
- AllocationSiteMode allocation_mode) { |
- switch (allocation_mode) { |
- case TRACK_ALLOCATION_SITE: |
- return FastCloneShallowArrayTrack(); |
- case DONT_TRACK_ALLOCATION_SITE: |
- return FastCloneShallowArrayDontTrack(); |
- default: |
- UNREACHABLE(); |
- } |
- return Handle<Code>::null(); |
-} |
- |
-// static |
-int ConstructorBuiltinsAssembler::FastCloneShallowObjectPropertiesCount( |
- int literal_length) { |
- // This heuristic of setting empty literals to have |
- // kInitialGlobalObjectUnusedPropertiesCount must remain in-sync with the |
- // runtime. |
- // TODO(verwaest): Unify this with the heuristic in the runtime. |
- return literal_length == 0 |
- ? JSObject::kInitialGlobalObjectUnusedPropertiesCount |
- : literal_length; |
-} |
- |
-Node* ConstructorBuiltinsAssembler::EmitFastCloneShallowObject( |
- CodeAssemblerLabel* call_runtime, Node* closure, Node* literals_index, |
- Node* properties_count) { |
- Node* cell = LoadObjectField(closure, JSFunction::kFeedbackVectorOffset); |
- Node* feedback_vector = LoadObjectField(cell, Cell::kValueOffset); |
- Node* allocation_site = LoadFixedArrayElement( |
- feedback_vector, literals_index, 0, CodeStubAssembler::SMI_PARAMETERS); |
- GotoIf(IsUndefined(allocation_site), call_runtime); |
- |
- // Calculate the object and allocation size based on the properties count. |
- Node* object_size = IntPtrAdd(WordShl(properties_count, kPointerSizeLog2), |
- IntPtrConstant(JSObject::kHeaderSize)); |
- Node* allocation_size = object_size; |
- if (FLAG_allocation_site_pretenuring) { |
- allocation_size = |
- IntPtrAdd(object_size, IntPtrConstant(AllocationMemento::kSize)); |
- } |
- Node* boilerplate = |
- LoadObjectField(allocation_site, AllocationSite::kTransitionInfoOffset); |
- Node* boilerplate_map = LoadMap(boilerplate); |
- Node* instance_size = LoadMapInstanceSize(boilerplate_map); |
- Node* size_in_words = WordShr(object_size, kPointerSizeLog2); |
- GotoIfNot(WordEqual(instance_size, size_in_words), call_runtime); |
- |
- Node* copy = AllocateInNewSpace(allocation_size); |
- |
- // Copy boilerplate elements. |
- Variable offset(this, MachineType::PointerRepresentation()); |
- offset.Bind(IntPtrConstant(-kHeapObjectTag)); |
- Node* end_offset = IntPtrAdd(object_size, offset.value()); |
- Label loop_body(this, &offset), loop_check(this, &offset); |
- // We should always have an object size greater than zero. |
- Goto(&loop_body); |
- Bind(&loop_body); |
- { |
- // The Allocate above guarantees that the copy lies in new space. This |
- // allows us to skip write barriers. This is necessary since we may also be |
- // copying unboxed doubles. |
- Node* field = Load(MachineType::IntPtr(), boilerplate, offset.value()); |
- StoreNoWriteBarrier(MachineType::PointerRepresentation(), copy, |
- offset.value(), field); |
- Goto(&loop_check); |
- } |
- Bind(&loop_check); |
- { |
- offset.Bind(IntPtrAdd(offset.value(), IntPtrConstant(kPointerSize))); |
- GotoIfNot(IntPtrGreaterThanOrEqual(offset.value(), end_offset), &loop_body); |
- } |
- |
- if (FLAG_allocation_site_pretenuring) { |
- Node* memento = InnerAllocate(copy, object_size); |
- StoreMapNoWriteBarrier(memento, Heap::kAllocationMementoMapRootIndex); |
- StoreObjectFieldNoWriteBarrier( |
- memento, AllocationMemento::kAllocationSiteOffset, allocation_site); |
- Node* memento_create_count = LoadObjectField( |
- allocation_site, AllocationSite::kPretenureCreateCountOffset); |
- memento_create_count = |
- SmiAdd(memento_create_count, SmiConstant(Smi::FromInt(1))); |
- StoreObjectFieldNoWriteBarrier(allocation_site, |
- AllocationSite::kPretenureCreateCountOffset, |
- memento_create_count); |
- } |
- |
- // TODO(verwaest): Allocate and fill in double boxes. |
- return copy; |
-} |
- |
-void ConstructorBuiltinsAssembler::CreateFastCloneShallowObjectBuiltin( |
- int properties_count) { |
- DCHECK_GE(properties_count, 0); |
- DCHECK_LE(properties_count, kMaximumClonedShallowObjectProperties); |
- Label call_runtime(this); |
- Node* closure = Parameter(0); |
- Node* literals_index = Parameter(1); |
- |
- Node* properties_count_node = |
- IntPtrConstant(FastCloneShallowObjectPropertiesCount(properties_count)); |
- Node* copy = EmitFastCloneShallowObject( |
- &call_runtime, closure, literals_index, properties_count_node); |
- Return(copy); |
- |
- Bind(&call_runtime); |
- Node* constant_properties = Parameter(2); |
- Node* flags = Parameter(3); |
- Node* context = Parameter(4); |
- TailCallRuntime(Runtime::kCreateObjectLiteral, context, closure, |
- literals_index, constant_properties, flags); |
-} |
- |
-#define SHALLOW_OBJECT_BUILTIN(props) \ |
- TF_BUILTIN(FastCloneShallowObject##props, ConstructorBuiltinsAssembler) { \ |
- CreateFastCloneShallowObjectBuiltin(props); \ |
- } |
- |
-SHALLOW_OBJECT_BUILTIN(0); |
-SHALLOW_OBJECT_BUILTIN(1); |
-SHALLOW_OBJECT_BUILTIN(2); |
-SHALLOW_OBJECT_BUILTIN(3); |
-SHALLOW_OBJECT_BUILTIN(4); |
-SHALLOW_OBJECT_BUILTIN(5); |
-SHALLOW_OBJECT_BUILTIN(6); |
- |
-Handle<Code> Builtins::NewCloneShallowObject(int length) { |
- switch (length) { |
- case 0: |
- return FastCloneShallowObject0(); |
- case 1: |
- return FastCloneShallowObject1(); |
- case 2: |
- return FastCloneShallowObject2(); |
- case 3: |
- return FastCloneShallowObject3(); |
- case 4: |
- return FastCloneShallowObject4(); |
- case 5: |
- return FastCloneShallowObject5(); |
- case 6: |
- return FastCloneShallowObject6(); |
- default: |
- UNREACHABLE(); |
- } |
- return Handle<Code>::null(); |
-} |
- |
-} // namespace internal |
-} // namespace v8 |