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