| Index: src/compiler/js-typed-lowering.cc
|
| diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc
|
| index 851b6d69c27ae521ed1cd8a8afec299eacb4b7b9..f0c4b81137b9cdb2cf2503fe6ad86916938f99d6 100644
|
| --- a/src/compiler/js-typed-lowering.cc
|
| +++ b/src/compiler/js-typed-lowering.cc
|
| @@ -11,7 +11,6 @@
|
| #include "src/compiler/node-matchers.h"
|
| #include "src/compiler/node-properties.h"
|
| #include "src/compiler/operator-properties.h"
|
| -#include "src/compiler/state-values-utils.h"
|
| #include "src/type-cache.h"
|
| #include "src/types.h"
|
|
|
| @@ -19,86 +18,6 @@ namespace v8 {
|
| namespace internal {
|
| namespace compiler {
|
|
|
| -namespace {
|
| -
|
| -// A helper class to construct inline allocations on the simplified operator
|
| -// level. This keeps track of the effect chain for initial stores on a newly
|
| -// allocated object and also provides helpers for commonly allocated objects.
|
| -class AllocationBuilder final {
|
| - public:
|
| - AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control)
|
| - : jsgraph_(jsgraph),
|
| - allocation_(nullptr),
|
| - effect_(effect),
|
| - control_(control) {}
|
| -
|
| - // Primitive allocation of static size.
|
| - void Allocate(int size, PretenureFlag pretenure = NOT_TENURED) {
|
| - effect_ = graph()->NewNode(common()->BeginRegion(), effect_);
|
| - allocation_ =
|
| - graph()->NewNode(simplified()->Allocate(pretenure),
|
| - jsgraph()->Constant(size), effect_, control_);
|
| - effect_ = allocation_;
|
| - }
|
| -
|
| - // Primitive store into a field.
|
| - void Store(const FieldAccess& access, Node* value) {
|
| - effect_ = graph()->NewNode(simplified()->StoreField(access), allocation_,
|
| - value, effect_, control_);
|
| - }
|
| -
|
| - // Primitive store into an element.
|
| - void Store(ElementAccess const& access, Node* index, Node* value) {
|
| - effect_ = graph()->NewNode(simplified()->StoreElement(access), allocation_,
|
| - index, value, effect_, control_);
|
| - }
|
| -
|
| - // Compound allocation of a FixedArray.
|
| - void AllocateArray(int length, Handle<Map> map,
|
| - PretenureFlag pretenure = NOT_TENURED) {
|
| - DCHECK(map->instance_type() == FIXED_ARRAY_TYPE ||
|
| - map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE);
|
| - int size = (map->instance_type() == FIXED_ARRAY_TYPE)
|
| - ? FixedArray::SizeFor(length)
|
| - : FixedDoubleArray::SizeFor(length);
|
| - Allocate(size, pretenure);
|
| - Store(AccessBuilder::ForMap(), map);
|
| - Store(AccessBuilder::ForFixedArrayLength(), jsgraph()->Constant(length));
|
| - }
|
| -
|
| - // Compound store of a constant into a field.
|
| - void Store(const FieldAccess& access, Handle<Object> value) {
|
| - Store(access, jsgraph()->Constant(value));
|
| - }
|
| -
|
| - void FinishAndChange(Node* node) {
|
| - NodeProperties::SetType(allocation_, NodeProperties::GetType(node));
|
| - node->ReplaceInput(0, allocation_);
|
| - node->ReplaceInput(1, effect_);
|
| - node->TrimInputCount(2);
|
| - NodeProperties::ChangeOp(node, common()->FinishRegion());
|
| - }
|
| -
|
| - Node* Finish() {
|
| - return graph()->NewNode(common()->FinishRegion(), allocation_, effect_);
|
| - }
|
| -
|
| - protected:
|
| - JSGraph* jsgraph() { return jsgraph_; }
|
| - Graph* graph() { return jsgraph_->graph(); }
|
| - CommonOperatorBuilder* common() { return jsgraph_->common(); }
|
| - SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); }
|
| -
|
| - private:
|
| - JSGraph* const jsgraph_;
|
| - Node* allocation_;
|
| - Node* effect_;
|
| - Node* control_;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -
|
| // A helper class to simplify the process of reducing a single binop node with a
|
| // JSOperator. This class manages the rewriting of context, control, and effect
|
| // dependencies during lowering of a binop and contains numerous helper
|
| @@ -1432,505 +1351,6 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
|
| }
|
|
|
|
|
| -namespace {
|
| -
|
| -// Maximum instance size for which allocations will be inlined.
|
| -const int kMaxInlineInstanceSize = 64 * kPointerSize;
|
| -
|
| -
|
| -// Checks whether allocation using the given constructor can be inlined.
|
| -bool IsAllocationInlineable(Handle<JSFunction> constructor) {
|
| - // TODO(bmeurer): Further relax restrictions on inlining, i.e.
|
| - // instance type and maybe instance size (inobject properties
|
| - // are limited anyways by the runtime).
|
| - return constructor->has_initial_map() &&
|
| - constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
|
| - constructor->initial_map()->instance_size() < kMaxInlineInstanceSize;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreate(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
|
| - Node* const target = NodeProperties::GetValueInput(node, 0);
|
| - Type* const target_type = NodeProperties::GetType(target);
|
| - Node* const new_target = NodeProperties::GetValueInput(node, 1);
|
| - Node* const effect = NodeProperties::GetEffectInput(node);
|
| - // TODO(turbofan): Add support for NewTarget passed to JSCreate.
|
| - if (target != new_target) return NoChange();
|
| - // Extract constructor function.
|
| - if (target_type->IsConstant() &&
|
| - target_type->AsConstant()->Value()->IsJSFunction()) {
|
| - Handle<JSFunction> constructor =
|
| - Handle<JSFunction>::cast(target_type->AsConstant()->Value());
|
| - DCHECK(constructor->IsConstructor());
|
| - // Force completion of inobject slack tracking before
|
| - // generating code to finalize the instance size.
|
| - constructor->CompleteInobjectSlackTrackingIfActive();
|
| -
|
| - // TODO(bmeurer): We fall back to the runtime in case we cannot inline
|
| - // the allocation here, which is sort of expensive. We should think about
|
| - // a soft fallback to some NewObjectCodeStub.
|
| - if (IsAllocationInlineable(constructor)) {
|
| - // Compute instance size from initial map of {constructor}.
|
| - Handle<Map> initial_map(constructor->initial_map(), isolate());
|
| - int const instance_size = initial_map->instance_size();
|
| -
|
| - // Add a dependency on the {initial_map} to make sure that this code is
|
| - // deoptimized whenever the {initial_map} of the {constructor} changes.
|
| - dependencies()->AssumeInitialMapCantChange(initial_map);
|
| -
|
| - // Emit code to allocate the JSObject instance for the {constructor}.
|
| - AllocationBuilder a(jsgraph(), effect, graph()->start());
|
| - a.Allocate(instance_size);
|
| - a.Store(AccessBuilder::ForMap(), initial_map);
|
| - a.Store(AccessBuilder::ForJSObjectProperties(),
|
| - jsgraph()->EmptyFixedArrayConstant());
|
| - a.Store(AccessBuilder::ForJSObjectElements(),
|
| - jsgraph()->EmptyFixedArrayConstant());
|
| - for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
|
| - a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
|
| - jsgraph()->UndefinedConstant());
|
| - }
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| - }
|
| - }
|
| - return NoChange();
|
| -}
|
| -
|
| -
|
| -namespace {
|
| -
|
| -// Retrieves the frame state holding actual argument values.
|
| -Node* GetArgumentsFrameState(Node* frame_state) {
|
| - Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
| - FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state);
|
| - return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
|
| - ? outer_state
|
| - : frame_state;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
|
| - CreateArgumentsType type = CreateArgumentsTypeOf(node->op());
|
| - Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
|
| - Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
| - FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
|
| -
|
| - // Use the ArgumentsAccessStub for materializing both mapped and unmapped
|
| - // arguments object, but only for non-inlined (i.e. outermost) frames.
|
| - if (outer_state->opcode() != IrOpcode::kFrameState) {
|
| - if (type != CreateArgumentsType::kRestParameter) {
|
| - // TODO(bmeurer): Cleanup this mess at some point.
|
| - Isolate* isolate = jsgraph()->isolate();
|
| - int parameter_count = state_info.parameter_count() - 1;
|
| - int parameter_offset = parameter_count * kPointerSize;
|
| - int offset = StandardFrameConstants::kCallerSPOffset + parameter_offset;
|
| - Node* parameter_pointer = graph()->NewNode(
|
| - machine()->IntAdd(), graph()->NewNode(machine()->LoadFramePointer()),
|
| - jsgraph()->IntPtrConstant(offset));
|
| - Handle<SharedFunctionInfo> shared;
|
| - if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
|
| - bool unmapped = type == CreateArgumentsType::kUnmappedArguments;
|
| - Callable callable = CodeFactory::ArgumentsAccess(
|
| - isolate, unmapped, shared->has_duplicate_parameters());
|
| - CallDescriptor* desc = Linkage::GetStubCallDescriptor(
|
| - isolate, graph()->zone(), callable.descriptor(), 0,
|
| - CallDescriptor::kNeedsFrameState);
|
| - const Operator* new_op = common()->Call(desc);
|
| - Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
| - node->InsertInput(graph()->zone(), 0, stub_code);
|
| - node->InsertInput(graph()->zone(), 2,
|
| - jsgraph()->Constant(parameter_count));
|
| - node->InsertInput(graph()->zone(), 3, parameter_pointer);
|
| - NodeProperties::ChangeOp(node, new_op);
|
| - return Changed(node);
|
| - } else {
|
| - Callable callable = CodeFactory::FastNewRestParameter(isolate());
|
| - CallDescriptor* desc = Linkage::GetStubCallDescriptor(
|
| - isolate(), graph()->zone(), callable.descriptor(), 0,
|
| - CallDescriptor::kNeedsFrameState);
|
| - const Operator* new_op = common()->Call(desc);
|
| - Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
| - node->InsertInput(graph()->zone(), 0, stub_code);
|
| - NodeProperties::ChangeOp(node, new_op);
|
| - return Changed(node);
|
| - }
|
| - } else if (outer_state->opcode() == IrOpcode::kFrameState) {
|
| - // Use inline allocation for all mapped arguments objects within inlined
|
| - // (i.e. non-outermost) frames, independent of the object size.
|
| - if (type == CreateArgumentsType::kMappedArguments) {
|
| - Handle<SharedFunctionInfo> shared;
|
| - if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
|
| - Node* const callee = NodeProperties::GetValueInput(node, 0);
|
| - Node* const control = NodeProperties::GetControlInput(node);
|
| - Node* const context = NodeProperties::GetContextInput(node);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - // TODO(mstarzinger): Duplicate parameters are not handled yet.
|
| - if (shared->has_duplicate_parameters()) return NoChange();
|
| - // Choose the correct frame state and frame state info depending on
|
| - // whether there conceptually is an arguments adaptor frame in the call
|
| - // chain.
|
| - Node* const args_state = GetArgumentsFrameState(frame_state);
|
| - FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
|
| - // Prepare element backing store to be used by arguments object.
|
| - bool has_aliased_arguments = false;
|
| - Node* const elements = AllocateAliasedArguments(
|
| - effect, control, args_state, context, shared, &has_aliased_arguments);
|
| - effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
|
| - // Load the arguments object map from the current native context.
|
| - Node* const load_native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - Node* const load_arguments_map = effect = graph()->NewNode(
|
| - simplified()->LoadField(AccessBuilder::ForContextSlot(
|
| - has_aliased_arguments ? Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX
|
| - : Context::SLOPPY_ARGUMENTS_MAP_INDEX)),
|
| - load_native_context, effect, control);
|
| - // Actually allocate and initialize the arguments object.
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - Node* properties = jsgraph()->EmptyFixedArrayConstant();
|
| - int length = args_state_info.parameter_count() - 1; // Minus receiver.
|
| - STATIC_ASSERT(Heap::kSloppyArgumentsObjectSize == 5 * kPointerSize);
|
| - a.Allocate(Heap::kSloppyArgumentsObjectSize);
|
| - a.Store(AccessBuilder::ForMap(), load_arguments_map);
|
| - a.Store(AccessBuilder::ForJSObjectProperties(), properties);
|
| - a.Store(AccessBuilder::ForJSObjectElements(), elements);
|
| - a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
|
| - a.Store(AccessBuilder::ForArgumentsCallee(), callee);
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| - } else if (type == CreateArgumentsType::kUnmappedArguments) {
|
| - // Use inline allocation for all unmapped arguments objects within inlined
|
| - // (i.e. non-outermost) frames, independent of the object size.
|
| - Node* const control = NodeProperties::GetControlInput(node);
|
| - Node* const context = NodeProperties::GetContextInput(node);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - // Choose the correct frame state and frame state info depending on
|
| - // whether there conceptually is an arguments adaptor frame in the call
|
| - // chain.
|
| - Node* const args_state = GetArgumentsFrameState(frame_state);
|
| - FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
|
| - // Prepare element backing store to be used by arguments object.
|
| - Node* const elements = AllocateArguments(effect, control, args_state);
|
| - effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
|
| - // Load the arguments object map from the current native context.
|
| - Node* const load_native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - Node* const load_arguments_map = effect = graph()->NewNode(
|
| - simplified()->LoadField(AccessBuilder::ForContextSlot(
|
| - Context::STRICT_ARGUMENTS_MAP_INDEX)),
|
| - load_native_context, effect, control);
|
| - // Actually allocate and initialize the arguments object.
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - Node* properties = jsgraph()->EmptyFixedArrayConstant();
|
| - int length = args_state_info.parameter_count() - 1; // Minus receiver.
|
| - STATIC_ASSERT(Heap::kStrictArgumentsObjectSize == 4 * kPointerSize);
|
| - a.Allocate(Heap::kStrictArgumentsObjectSize);
|
| - a.Store(AccessBuilder::ForMap(), load_arguments_map);
|
| - a.Store(AccessBuilder::ForJSObjectProperties(), properties);
|
| - a.Store(AccessBuilder::ForJSObjectElements(), elements);
|
| - a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| - } else if (type == CreateArgumentsType::kRestParameter) {
|
| - Handle<SharedFunctionInfo> shared;
|
| - if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
|
| - int start_index = shared->internal_formal_parameter_count();
|
| - // Use inline allocation for all unmapped arguments objects within inlined
|
| - // (i.e. non-outermost) frames, independent of the object size.
|
| - Node* const control = NodeProperties::GetControlInput(node);
|
| - Node* const context = NodeProperties::GetContextInput(node);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - // Choose the correct frame state and frame state info depending on
|
| - // whether there conceptually is an arguments adaptor frame in the call
|
| - // chain.
|
| - Node* const args_state = GetArgumentsFrameState(frame_state);
|
| - FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
|
| - // Prepare element backing store to be used by the rest array.
|
| - Node* const elements =
|
| - AllocateRestArguments(effect, control, args_state, start_index);
|
| - effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
|
| - // Load the JSArray object map from the current native context.
|
| - Node* const load_native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - Node* const load_jsarray_map = effect = graph()->NewNode(
|
| - simplified()->LoadField(AccessBuilder::ForContextSlot(
|
| - Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX)),
|
| - load_native_context, effect, control);
|
| - // Actually allocate and initialize the jsarray.
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - Node* properties = jsgraph()->EmptyFixedArrayConstant();
|
| -
|
| - // -1 to minus receiver
|
| - int argument_count = args_state_info.parameter_count() - 1;
|
| - int length = std::max(0, argument_count - start_index);
|
| - STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
|
| - a.Allocate(JSArray::kSize);
|
| - a.Store(AccessBuilder::ForMap(), load_jsarray_map);
|
| - a.Store(AccessBuilder::ForJSObjectProperties(), properties);
|
| - a.Store(AccessBuilder::ForJSObjectElements(), elements);
|
| - a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS),
|
| - jsgraph()->Constant(length));
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| - }
|
| - }
|
| -
|
| - return NoChange();
|
| -}
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceNewArray(Node* node, Node* length,
|
| - int capacity,
|
| - Handle<AllocationSite> site) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
|
| - Node* context = NodeProperties::GetContextInput(node);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - Node* control = NodeProperties::GetControlInput(node);
|
| -
|
| - // Extract transition and tenuring feedback from the {site} and add
|
| - // appropriate code dependencies on the {site} if deoptimization is
|
| - // enabled.
|
| - PretenureFlag pretenure = site->GetPretenureMode();
|
| - ElementsKind elements_kind = site->GetElementsKind();
|
| - DCHECK(IsFastElementsKind(elements_kind));
|
| - if (flags() & kDeoptimizationEnabled) {
|
| - dependencies()->AssumeTenuringDecision(site);
|
| - dependencies()->AssumeTransitionStable(site);
|
| - }
|
| -
|
| - // Retrieve the initial map for the array from the appropriate native context.
|
| - Node* native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - Node* js_array_map = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::ArrayMapIndex(elements_kind), true),
|
| - native_context, native_context, effect);
|
| -
|
| - // Setup elements and properties.
|
| - Node* elements;
|
| - if (capacity == 0) {
|
| - elements = jsgraph()->EmptyFixedArrayConstant();
|
| - } else {
|
| - elements = effect =
|
| - AllocateElements(effect, control, elements_kind, capacity, pretenure);
|
| - }
|
| - Node* properties = jsgraph()->EmptyFixedArrayConstant();
|
| -
|
| - // Perform the allocation of the actual JSArray object.
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - a.Allocate(JSArray::kSize, pretenure);
|
| - a.Store(AccessBuilder::ForMap(), js_array_map);
|
| - a.Store(AccessBuilder::ForJSObjectProperties(), properties);
|
| - a.Store(AccessBuilder::ForJSObjectElements(), elements);
|
| - a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| -}
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreateArray(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
|
| - CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
|
| - Node* target = NodeProperties::GetValueInput(node, 0);
|
| - Node* new_target = NodeProperties::GetValueInput(node, 1);
|
| -
|
| - // TODO(bmeurer): Optimize the subclassing case.
|
| - if (target != new_target) return NoChange();
|
| -
|
| - // Check if we have a feedback {site} on the {node}.
|
| - Handle<AllocationSite> site = p.site();
|
| - if (p.site().is_null()) return NoChange();
|
| -
|
| - // Attempt to inline calls to the Array constructor for the relevant cases
|
| - // where either no arguments are provided, or exactly one unsigned number
|
| - // argument is given.
|
| - if (site->CanInlineCall()) {
|
| - if (p.arity() == 0) {
|
| - Node* length = jsgraph()->ZeroConstant();
|
| - int capacity = JSArray::kPreallocatedArrayElements;
|
| - return ReduceNewArray(node, length, capacity, site);
|
| - } else if (p.arity() == 1) {
|
| - Node* length = NodeProperties::GetValueInput(node, 2);
|
| - Type* length_type = NodeProperties::GetType(length);
|
| - if (length_type->Is(type_cache_.kElementLoopUnrollType)) {
|
| - int capacity = static_cast<int>(length_type->Max());
|
| - return ReduceNewArray(node, length, capacity, site);
|
| - }
|
| - }
|
| - }
|
| -
|
| - return NoChange();
|
| -}
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreateIterResultObject(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
|
| - Node* value = NodeProperties::GetValueInput(node, 0);
|
| - Node* done = NodeProperties::GetValueInput(node, 1);
|
| - Node* context = NodeProperties::GetContextInput(node);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| -
|
| - // Load the JSIteratorResult map for the {context}.
|
| - Node* native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - Node* iterator_result_map = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::ITERATOR_RESULT_MAP_INDEX, true),
|
| - native_context, native_context, effect);
|
| -
|
| - // Emit code to allocate the JSIteratorResult instance.
|
| - AllocationBuilder a(jsgraph(), effect, graph()->start());
|
| - a.Allocate(JSIteratorResult::kSize);
|
| - a.Store(AccessBuilder::ForMap(), iterator_result_map);
|
| - a.Store(AccessBuilder::ForJSObjectProperties(),
|
| - jsgraph()->EmptyFixedArrayConstant());
|
| - a.Store(AccessBuilder::ForJSObjectElements(),
|
| - jsgraph()->EmptyFixedArrayConstant());
|
| - a.Store(AccessBuilder::ForJSIteratorResultValue(), value);
|
| - a.Store(AccessBuilder::ForJSIteratorResultDone(), done);
|
| - STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| -}
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
|
| - int slot_count = OpParameter<int>(node->op());
|
| - Node* const closure = NodeProperties::GetValueInput(node, 0);
|
| -
|
| - // Use inline allocation for function contexts up to a size limit.
|
| - if (slot_count < kFunctionContextAllocationLimit) {
|
| - // JSCreateFunctionContext[slot_count < limit]](fun)
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - Node* control = NodeProperties::GetControlInput(node);
|
| - Node* context = NodeProperties::GetContextInput(node);
|
| - Node* extension = jsgraph()->TheHoleConstant();
|
| - Node* native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
|
| - int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
|
| - a.AllocateArray(context_length, factory()->function_context_map());
|
| - a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
|
| - native_context);
|
| - for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
|
| - a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
|
| - }
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| - }
|
| -
|
| - return NoChange();
|
| -}
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
|
| - Node* object = NodeProperties::GetValueInput(node, 0);
|
| - Node* closure = NodeProperties::GetValueInput(node, 1);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - Node* control = NodeProperties::GetControlInput(node);
|
| - Node* context = NodeProperties::GetContextInput(node);
|
| - Node* native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
|
| - a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
|
| - a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), object);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
|
| - native_context);
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| -}
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreateCatchContext(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
|
| - Handle<String> name = OpParameter<Handle<String>>(node);
|
| - Node* exception = NodeProperties::GetValueInput(node, 0);
|
| - Node* closure = NodeProperties::GetValueInput(node, 1);
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - Node* control = NodeProperties::GetControlInput(node);
|
| - Node* context = NodeProperties::GetContextInput(node);
|
| - Node* native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
|
| - a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1,
|
| - factory()->catch_context_map());
|
| - a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), name);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
|
| - native_context);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX),
|
| - exception);
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| -}
|
| -
|
| -
|
| -Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) {
|
| - DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
|
| - Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
|
| - int context_length = scope_info->ContextLength();
|
| - Node* const closure = NodeProperties::GetValueInput(node, 0);
|
| -
|
| - // Use inline allocation for block contexts up to a size limit.
|
| - if (context_length < kBlockContextAllocationLimit) {
|
| - // JSCreateBlockContext[scope[length < limit]](fun)
|
| - Node* effect = NodeProperties::GetEffectInput(node);
|
| - Node* control = NodeProperties::GetControlInput(node);
|
| - Node* context = NodeProperties::GetContextInput(node);
|
| - Node* extension = jsgraph()->Constant(scope_info);
|
| - Node* native_context = effect = graph()->NewNode(
|
| - javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
|
| - context, context, effect);
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
|
| - a.AllocateArray(context_length, factory()->block_context_map());
|
| - a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
|
| - a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
|
| - native_context);
|
| - for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
|
| - a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
|
| - }
|
| - RelaxControls(node);
|
| - a.FinishAndChange(node);
|
| - return Changed(node);
|
| - }
|
| -
|
| - return NoChange();
|
| -}
|
| -
|
| -
|
| Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
|
| DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
|
| CallConstructParameters const& p = CallConstructParametersOf(node->op());
|
| @@ -2313,22 +1733,6 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
| return ReduceJSStoreContext(node);
|
| case IrOpcode::kJSConvertReceiver:
|
| return ReduceJSConvertReceiver(node);
|
| - case IrOpcode::kJSCreate:
|
| - return ReduceJSCreate(node);
|
| - case IrOpcode::kJSCreateArguments:
|
| - return ReduceJSCreateArguments(node);
|
| - case IrOpcode::kJSCreateArray:
|
| - return ReduceJSCreateArray(node);
|
| - case IrOpcode::kJSCreateIterResultObject:
|
| - return ReduceJSCreateIterResultObject(node);
|
| - case IrOpcode::kJSCreateFunctionContext:
|
| - return ReduceJSCreateFunctionContext(node);
|
| - case IrOpcode::kJSCreateWithContext:
|
| - return ReduceJSCreateWithContext(node);
|
| - case IrOpcode::kJSCreateCatchContext:
|
| - return ReduceJSCreateCatchContext(node);
|
| - case IrOpcode::kJSCreateBlockContext:
|
| - return ReduceJSCreateBlockContext(node);
|
| case IrOpcode::kJSCallConstruct:
|
| return ReduceJSCallConstruct(node);
|
| case IrOpcode::kJSCallFunction:
|
| @@ -2355,139 +1759,6 @@ Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
|
| }
|
|
|
|
|
| -// Helper that allocates a FixedArray holding argument values recorded in the
|
| -// given {frame_state}. Serves as backing store for JSCreateArguments nodes.
|
| -Node* JSTypedLowering::AllocateArguments(Node* effect, Node* control,
|
| - Node* frame_state) {
|
| - FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
|
| - int argument_count = state_info.parameter_count() - 1; // Minus receiver.
|
| - if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
|
| -
|
| - // Prepare an iterator over argument values recorded in the frame state.
|
| - Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
|
| - StateValuesAccess parameters_access(parameters);
|
| - auto parameters_it = ++parameters_access.begin();
|
| -
|
| - // Actually allocate the backing store.
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - a.AllocateArray(argument_count, factory()->fixed_array_map());
|
| - for (int i = 0; i < argument_count; ++i, ++parameters_it) {
|
| - a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
|
| - }
|
| - return a.Finish();
|
| -}
|
| -
|
| -
|
| -// Helper that allocates a FixedArray holding argument values recorded in the
|
| -// given {frame_state}. Serves as backing store for JSCreateArguments nodes.
|
| -Node* JSTypedLowering::AllocateRestArguments(Node* effect, Node* control,
|
| - Node* frame_state,
|
| - int start_index) {
|
| - FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
|
| - int argument_count = state_info.parameter_count() - 1; // Minus receiver.
|
| - int num_elements = std::max(0, argument_count - start_index);
|
| - if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
|
| -
|
| - // Prepare an iterator over argument values recorded in the frame state.
|
| - Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
|
| - StateValuesAccess parameters_access(parameters);
|
| - auto parameters_it = ++parameters_access.begin();
|
| -
|
| - // Skip unused arguments.
|
| - for (int i = 0; i < start_index; i++) {
|
| - ++parameters_it;
|
| - }
|
| -
|
| - // Actually allocate the backing store.
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - a.AllocateArray(num_elements, factory()->fixed_array_map());
|
| - for (int i = 0; i < num_elements; ++i, ++parameters_it) {
|
| - a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
|
| - }
|
| - return a.Finish();
|
| -}
|
| -
|
| -
|
| -// Helper that allocates a FixedArray serving as a parameter map for values
|
| -// recorded in the given {frame_state}. Some elements map to slots within the
|
| -// given {context}. Serves as backing store for JSCreateArguments nodes.
|
| -Node* JSTypedLowering::AllocateAliasedArguments(
|
| - Node* effect, Node* control, Node* frame_state, Node* context,
|
| - Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) {
|
| - FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
|
| - int argument_count = state_info.parameter_count() - 1; // Minus receiver.
|
| - if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
|
| -
|
| - // If there is no aliasing, the arguments object elements are not special in
|
| - // any way, we can just return an unmapped backing store instead.
|
| - int parameter_count = shared->internal_formal_parameter_count();
|
| - if (parameter_count == 0) {
|
| - return AllocateArguments(effect, control, frame_state);
|
| - }
|
| -
|
| - // Calculate number of argument values being aliased/mapped.
|
| - int mapped_count = Min(argument_count, parameter_count);
|
| - *has_aliased_arguments = true;
|
| -
|
| - // Prepare an iterator over argument values recorded in the frame state.
|
| - Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
|
| - StateValuesAccess parameters_access(parameters);
|
| - auto paratemers_it = ++parameters_access.begin();
|
| -
|
| - // The unmapped argument values recorded in the frame state are stored yet
|
| - // another indirection away and then linked into the parameter map below,
|
| - // whereas mapped argument values are replaced with a hole instead.
|
| - AllocationBuilder aa(jsgraph(), effect, control);
|
| - aa.AllocateArray(argument_count, factory()->fixed_array_map());
|
| - for (int i = 0; i < mapped_count; ++i, ++paratemers_it) {
|
| - aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant());
|
| - }
|
| - for (int i = mapped_count; i < argument_count; ++i, ++paratemers_it) {
|
| - aa.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node);
|
| - }
|
| - Node* arguments = aa.Finish();
|
| -
|
| - // Actually allocate the backing store.
|
| - AllocationBuilder a(jsgraph(), arguments, control);
|
| - a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
|
| - a.Store(AccessBuilder::ForFixedArraySlot(0), context);
|
| - a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
|
| - for (int i = 0; i < mapped_count; ++i) {
|
| - int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
|
| - a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx));
|
| - }
|
| - return a.Finish();
|
| -}
|
| -
|
| -
|
| -Node* JSTypedLowering::AllocateElements(Node* effect, Node* control,
|
| - ElementsKind elements_kind,
|
| - int capacity, PretenureFlag pretenure) {
|
| - DCHECK_LE(1, capacity);
|
| - DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
|
| -
|
| - Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind)
|
| - ? factory()->fixed_double_array_map()
|
| - : factory()->fixed_array_map();
|
| - ElementAccess access = IsFastDoubleElementsKind(elements_kind)
|
| - ? AccessBuilder::ForFixedDoubleArrayElement()
|
| - : AccessBuilder::ForFixedArrayElement();
|
| - Node* value =
|
| - IsFastDoubleElementsKind(elements_kind)
|
| - ? jsgraph()->Float64Constant(bit_cast<double>(kHoleNanInt64))
|
| - : jsgraph()->TheHoleConstant();
|
| -
|
| - // Actually allocate the backing store.
|
| - AllocationBuilder a(jsgraph(), effect, control);
|
| - a.AllocateArray(capacity, elements_map, pretenure);
|
| - for (int i = 0; i < capacity; ++i) {
|
| - Node* index = jsgraph()->Constant(i);
|
| - a.Store(access, index, value);
|
| - }
|
| - return a.Finish();
|
| -}
|
| -
|
| -
|
| Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
|
|
|
|
|
|
|