// Copyright 2014 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/compiler/js-generic-lowering.h"
|
|
#include "src/ast/ast.h"
|
#include "src/builtins/builtins-constructor.h"
|
#include "src/code-factory.h"
|
#include "src/code-stubs.h"
|
#include "src/compiler/common-operator.h"
|
#include "src/compiler/js-graph.h"
|
#include "src/compiler/machine-operator.h"
|
#include "src/compiler/node-matchers.h"
|
#include "src/compiler/node-properties.h"
|
#include "src/compiler/operator-properties.h"
|
#include "src/feedback-vector.h"
|
#include "src/objects/scope-info.h"
|
|
namespace v8 {
|
namespace internal {
|
namespace compiler {
|
|
namespace {
|
|
CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
|
return OperatorProperties::HasFrameStateInput(node->op())
|
? CallDescriptor::kNeedsFrameState
|
: CallDescriptor::kNoFlags;
|
}
|
|
} // namespace
|
|
JSGenericLowering::JSGenericLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
|
|
JSGenericLowering::~JSGenericLowering() {}
|
|
|
Reduction JSGenericLowering::Reduce(Node* node) {
|
switch (node->opcode()) {
|
#define DECLARE_CASE(x) \
|
case IrOpcode::k##x: \
|
Lower##x(node); \
|
break;
|
JS_OP_LIST(DECLARE_CASE)
|
#undef DECLARE_CASE
|
default:
|
// Nothing to see.
|
return NoChange();
|
}
|
return Changed(node);
|
}
|
|
#define REPLACE_STUB_CALL(Name) \
|
void JSGenericLowering::LowerJS##Name(Node* node) { \
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node); \
|
Callable callable = Builtins::CallableFor(isolate(), Builtins::k##Name); \
|
ReplaceWithStubCall(node, callable, flags); \
|
}
|
REPLACE_STUB_CALL(Add)
|
REPLACE_STUB_CALL(Subtract)
|
REPLACE_STUB_CALL(Multiply)
|
REPLACE_STUB_CALL(Divide)
|
REPLACE_STUB_CALL(Modulus)
|
REPLACE_STUB_CALL(Exponentiate)
|
REPLACE_STUB_CALL(BitwiseAnd)
|
REPLACE_STUB_CALL(BitwiseOr)
|
REPLACE_STUB_CALL(BitwiseXor)
|
REPLACE_STUB_CALL(ShiftLeft)
|
REPLACE_STUB_CALL(ShiftRight)
|
REPLACE_STUB_CALL(ShiftRightLogical)
|
REPLACE_STUB_CALL(LessThan)
|
REPLACE_STUB_CALL(LessThanOrEqual)
|
REPLACE_STUB_CALL(GreaterThan)
|
REPLACE_STUB_CALL(GreaterThanOrEqual)
|
REPLACE_STUB_CALL(BitwiseNot)
|
REPLACE_STUB_CALL(Decrement)
|
REPLACE_STUB_CALL(Increment)
|
REPLACE_STUB_CALL(Negate)
|
REPLACE_STUB_CALL(HasProperty)
|
REPLACE_STUB_CALL(Equal)
|
REPLACE_STUB_CALL(ToInteger)
|
REPLACE_STUB_CALL(ToLength)
|
REPLACE_STUB_CALL(ToNumber)
|
REPLACE_STUB_CALL(ToNumberConvertBigInt)
|
REPLACE_STUB_CALL(ToNumeric)
|
REPLACE_STUB_CALL(ToName)
|
REPLACE_STUB_CALL(ToObject)
|
REPLACE_STUB_CALL(ToString)
|
REPLACE_STUB_CALL(ForInEnumerate)
|
REPLACE_STUB_CALL(FulfillPromise)
|
REPLACE_STUB_CALL(PerformPromiseThen)
|
REPLACE_STUB_CALL(PromiseResolve)
|
REPLACE_STUB_CALL(RejectPromise)
|
REPLACE_STUB_CALL(ResolvePromise)
|
#undef REPLACE_STUB_CALL
|
|
void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
|
CallDescriptor::Flags flags) {
|
ReplaceWithStubCall(node, callable, flags, node->op()->properties());
|
}
|
|
void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
|
CallDescriptor::Flags flags,
|
Operator::Properties properties) {
|
const CallInterfaceDescriptor& descriptor = callable.descriptor();
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), descriptor, descriptor.GetStackParameterCount(), flags,
|
properties);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
node->InsertInput(zone(), 0, stub_code);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
|
void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
|
Runtime::FunctionId f,
|
int nargs_override) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Operator::Properties properties = node->op()->properties();
|
const Runtime::Function* fun = Runtime::FunctionForId(f);
|
int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
|
auto call_descriptor =
|
Linkage::GetRuntimeCallDescriptor(zone(), f, nargs, properties, flags);
|
Node* ref = jsgraph()->ExternalConstant(ExternalReference::Create(f));
|
Node* arity = jsgraph()->Int32Constant(nargs);
|
node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
|
node->InsertInput(zone(), nargs + 1, ref);
|
node->InsertInput(zone(), nargs + 2, arity);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSStrictEqual(Node* node) {
|
// The === operator doesn't need the current context.
|
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
|
Callable callable = Builtins::CallableFor(isolate(), Builtins::kStrictEqual);
|
node->RemoveInput(4); // control
|
ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
|
Operator::kEliminatable);
|
}
|
|
void JSGenericLowering::LowerJSLoadProperty(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
const PropertyAccess& p = PropertyAccessOf(node->op());
|
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
|
if (outer_state->opcode() != IrOpcode::kFrameState) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kKeyedLoadICTrampoline);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kKeyedLoadIC);
|
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
|
node->InsertInput(zone(), 3, vector);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
}
|
|
void JSGenericLowering::LowerJSLoadNamed(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
NamedAccess const& p = NamedAccessOf(node->op());
|
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
|
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
|
if (outer_state->opcode() != IrOpcode::kFrameState) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kLoadICTrampoline);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
Callable callable = Builtins::CallableFor(isolate(), Builtins::kLoadIC);
|
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
|
node->InsertInput(zone(), 3, vector);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
}
|
|
|
void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
|
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
|
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
|
if (outer_state->opcode() != IrOpcode::kFrameState) {
|
Callable callable = CodeFactory::LoadGlobalIC(isolate(), p.typeof_mode());
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
Callable callable =
|
CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
|
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
|
node->InsertInput(zone(), 2, vector);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
}
|
|
void JSGenericLowering::LowerJSStoreProperty(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
PropertyAccess const& p = PropertyAccessOf(node->op());
|
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
|
if (outer_state->opcode() != IrOpcode::kFrameState) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kKeyedStoreICTrampoline);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kKeyedStoreIC);
|
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
|
node->InsertInput(zone(), 4, vector);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
}
|
|
void JSGenericLowering::LowerJSStoreNamed(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
NamedAccess const& p = NamedAccessOf(node->op());
|
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
|
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
|
if (outer_state->opcode() != IrOpcode::kFrameState) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kStoreICTrampoline);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
Callable callable = Builtins::CallableFor(isolate(), Builtins::kStoreIC);
|
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
|
node->InsertInput(zone(), 4, vector);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
}
|
|
void JSGenericLowering::LowerJSStoreNamedOwn(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
|
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
|
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
|
if (outer_state->opcode() != IrOpcode::kFrameState) {
|
Callable callable = CodeFactory::StoreOwnIC(isolate());
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate());
|
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
|
node->InsertInput(zone(), 4, vector);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
}
|
|
void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
|
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
|
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
|
if (outer_state->opcode() != IrOpcode::kFrameState) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kStoreGlobalICTrampoline);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
|
Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
|
node->InsertInput(zone(), 3, vector);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
}
|
|
void JSGenericLowering::LowerJSStoreDataPropertyInLiteral(Node* node) {
|
FeedbackParameter const& p = FeedbackParameterOf(node->op());
|
node->InsertInputs(zone(), 4, 2);
|
node->ReplaceInput(4, jsgraph()->HeapConstant(p.feedback().vector()));
|
node->ReplaceInput(5, jsgraph()->SmiConstant(p.feedback().index()));
|
ReplaceWithRuntimeCall(node, Runtime::kDefineDataPropertyInLiteral);
|
}
|
|
void JSGenericLowering::LowerJSStoreInArrayLiteral(Node* node) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kStoreInArrayLiteralIC);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
FeedbackParameter const& p = FeedbackParameterOf(node->op());
|
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
|
node->InsertInput(zone(), 4, jsgraph()->HeapConstant(p.feedback().vector()));
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kDeleteProperty);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSGetSuperConstructor(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kGetSuperConstructor);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) {
|
ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain);
|
}
|
|
void JSGenericLowering::LowerJSInstanceOf(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = Builtins::CallableFor(isolate(), Builtins::kInstanceOf);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kOrdinaryHasInstance);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSLoadContext(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
|
void JSGenericLowering::LowerJSStoreContext(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
|
void JSGenericLowering::LowerJSCreate(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kFastNewObject);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
|
void JSGenericLowering::LowerJSCreateArguments(Node* node) {
|
CreateArgumentsType const type = CreateArgumentsTypeOf(node->op());
|
switch (type) {
|
case CreateArgumentsType::kMappedArguments:
|
ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments_Generic);
|
break;
|
case CreateArgumentsType::kUnmappedArguments:
|
ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments);
|
break;
|
case CreateArgumentsType::kRestParameter:
|
ReplaceWithRuntimeCall(node, Runtime::kNewRestParameter);
|
break;
|
}
|
}
|
|
|
void JSGenericLowering::LowerJSCreateArray(Node* node) {
|
CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
|
int const arity = static_cast<int>(p.arity());
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), ArrayConstructorDescriptor{}, arity + 1,
|
CallDescriptor::kNeedsFrameState, node->op()->properties());
|
Node* stub_code = jsgraph()->ArrayConstructorStubConstant();
|
Node* stub_arity = jsgraph()->Int32Constant(arity);
|
MaybeHandle<AllocationSite> const maybe_site = p.site();
|
Handle<AllocationSite> site;
|
Node* type_info = maybe_site.ToHandle(&site) ? jsgraph()->HeapConstant(site)
|
: jsgraph()->UndefinedConstant();
|
Node* receiver = jsgraph()->UndefinedConstant();
|
node->InsertInput(zone(), 0, stub_code);
|
node->InsertInput(zone(), 3, stub_arity);
|
node->InsertInput(zone(), 4, type_info);
|
node->InsertInput(zone(), 5, receiver);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSCreateArrayIterator(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateCollectionIterator(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateBoundFunction(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSObjectIsArray(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateObject(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = Builtins::CallableFor(
|
isolate(), Builtins::kCreateObjectWithoutProperties);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSParseInt(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = Builtins::CallableFor(isolate(), Builtins::kParseInt);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSRegExpTest(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kRegExpPrototypeTestFast);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSCreateClosure(Node* node) {
|
CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
|
Handle<SharedFunctionInfo> const shared_info = p.shared_info();
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info));
|
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.feedback_cell()));
|
node->RemoveInput(4); // control
|
|
// Use the FastNewClosure builtin only for functions allocated in new space.
|
if (p.pretenure() == NOT_TENURED) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kFastNewClosure);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
ReplaceWithRuntimeCall(node, Runtime::kNewClosure_Tenured);
|
}
|
}
|
|
|
void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
|
const CreateFunctionContextParameters& parameters =
|
CreateFunctionContextParametersOf(node->op());
|
Handle<ScopeInfo> scope_info = parameters.scope_info();
|
int slot_count = parameters.slot_count();
|
ScopeType scope_type = parameters.scope_type();
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
|
if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
|
Callable callable =
|
CodeFactory::FastNewFunctionContext(isolate(), scope_type);
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
|
node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
|
ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
|
}
|
}
|
|
void JSGenericLowering::LowerJSCreateGeneratorObject(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kCreateGeneratorObject);
|
node->RemoveInput(4); // control
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateStringIterator(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreatePromise(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kCreateTypedArray);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
|
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
|
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
|
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
|
|
// Use the CreateShallowArrayLiteratlr builtin only for shallow boilerplates
|
// without properties up to the number of elements that the stubs can handle.
|
if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
|
p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kCreateShallowArrayLiteral);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
|
ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
|
}
|
}
|
|
void JSGenericLowering::LowerJSCreateEmptyLiteralArray(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
FeedbackParameter const& p = FeedbackParameterOf(node->op());
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
|
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
|
node->RemoveInput(4); // control
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kCreateEmptyArrayLiteral);
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
|
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
|
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
|
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
|
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
|
|
// Use the CreateShallowObjectLiteratal builtin only for shallow boilerplates
|
// without elements up to the number of properties that the stubs can handle.
|
if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
|
p.length() <=
|
ConstructorBuiltins::kMaximumClonedShallowObjectProperties) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kCreateShallowObjectLiteral);
|
ReplaceWithStubCall(node, callable, flags);
|
} else {
|
ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
|
}
|
}
|
|
void JSGenericLowering::LowerJSCloneObject(Node* node) {
|
CloneObjectParameters const& p = CloneObjectParametersOf(node->op());
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kCloneObjectIC);
|
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags()));
|
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
|
node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector()));
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
|
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kCreateRegExpLiteral);
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
|
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
|
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
|
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
|
void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
|
Handle<ScopeInfo> scope_info = ScopeInfoOf(node->op());
|
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
|
ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
|
}
|
|
void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
|
ConstructForwardVarargsParameters p =
|
ConstructForwardVarargsParametersOf(node->op());
|
int const arg_count = static_cast<int>(p.arity() - 2);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = CodeFactory::ConstructForwardVarargs(isolate());
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), callable.descriptor(), arg_count + 1, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
Node* stub_arity = jsgraph()->Int32Constant(arg_count);
|
Node* start_index = jsgraph()->Uint32Constant(p.start_index());
|
Node* new_target = node->InputAt(arg_count + 1);
|
Node* receiver = jsgraph()->UndefinedConstant();
|
node->RemoveInput(arg_count + 1); // Drop new target.
|
node->InsertInput(zone(), 0, stub_code);
|
node->InsertInput(zone(), 2, new_target);
|
node->InsertInput(zone(), 3, stub_arity);
|
node->InsertInput(zone(), 4, start_index);
|
node->InsertInput(zone(), 5, receiver);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSConstruct(Node* node) {
|
ConstructParameters const& p = ConstructParametersOf(node->op());
|
int const arg_count = static_cast<int>(p.arity() - 2);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = CodeFactory::Construct(isolate());
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), callable.descriptor(), arg_count + 1, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
Node* stub_arity = jsgraph()->Int32Constant(arg_count);
|
Node* new_target = node->InputAt(arg_count + 1);
|
Node* receiver = jsgraph()->UndefinedConstant();
|
node->RemoveInput(arg_count + 1); // Drop new target.
|
node->InsertInput(zone(), 0, stub_code);
|
node->InsertInput(zone(), 2, new_target);
|
node->InsertInput(zone(), 3, stub_arity);
|
node->InsertInput(zone(), 4, receiver);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
|
Callable callable =
|
Builtins::CallableFor(isolate(), Builtins::kConstructWithArrayLike);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
auto call_descriptor =
|
Linkage::GetStubCallDescriptor(zone(), callable.descriptor(), 1, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
Node* receiver = jsgraph()->UndefinedConstant();
|
Node* arguments_list = node->InputAt(1);
|
Node* new_target = node->InputAt(2);
|
node->InsertInput(zone(), 0, stub_code);
|
node->ReplaceInput(2, new_target);
|
node->ReplaceInput(3, arguments_list);
|
node->InsertInput(zone(), 4, receiver);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
|
ConstructParameters const& p = ConstructParametersOf(node->op());
|
int const arg_count = static_cast<int>(p.arity() - 2);
|
int const spread_index = arg_count;
|
int const new_target_index = arg_count + 1;
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = CodeFactory::ConstructWithSpread(isolate());
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), callable.descriptor(), arg_count, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
Node* stack_arg_count = jsgraph()->Int32Constant(arg_count - 1);
|
Node* new_target = node->InputAt(new_target_index);
|
Node* spread = node->InputAt(spread_index);
|
Node* receiver = jsgraph()->UndefinedConstant();
|
DCHECK(new_target_index > spread_index);
|
node->RemoveInput(new_target_index); // Drop new target.
|
node->RemoveInput(spread_index);
|
|
node->InsertInput(zone(), 0, stub_code);
|
node->InsertInput(zone(), 2, new_target);
|
node->InsertInput(zone(), 3, stack_arg_count);
|
node->InsertInput(zone(), 4, spread);
|
node->InsertInput(zone(), 5, receiver);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
|
CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
|
int const arg_count = static_cast<int>(p.arity() - 2);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = CodeFactory::CallForwardVarargs(isolate());
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), callable.descriptor(), arg_count + 1, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
Node* stub_arity = jsgraph()->Int32Constant(arg_count);
|
Node* start_index = jsgraph()->Uint32Constant(p.start_index());
|
node->InsertInput(zone(), 0, stub_code);
|
node->InsertInput(zone(), 2, stub_arity);
|
node->InsertInput(zone(), 3, start_index);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSCall(Node* node) {
|
CallParameters const& p = CallParametersOf(node->op());
|
int const arg_count = static_cast<int>(p.arity() - 2);
|
ConvertReceiverMode const mode = p.convert_mode();
|
Callable callable = CodeFactory::Call(isolate(), mode);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), callable.descriptor(), arg_count + 1, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
Node* stub_arity = jsgraph()->Int32Constant(arg_count);
|
node->InsertInput(zone(), 0, stub_code);
|
node->InsertInput(zone(), 2, stub_arity);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
|
Callable callable = CodeFactory::CallWithArrayLike(isolate());
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
auto call_descriptor =
|
Linkage::GetStubCallDescriptor(zone(), callable.descriptor(), 1, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
Node* receiver = node->InputAt(1);
|
Node* arguments_list = node->InputAt(2);
|
node->InsertInput(zone(), 0, stub_code);
|
node->ReplaceInput(3, receiver);
|
node->ReplaceInput(2, arguments_list);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSCallWithSpread(Node* node) {
|
CallParameters const& p = CallParametersOf(node->op());
|
int const arg_count = static_cast<int>(p.arity() - 2);
|
int const spread_index = static_cast<int>(p.arity() + 1);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = CodeFactory::CallWithSpread(isolate());
|
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
zone(), callable.descriptor(), arg_count, flags);
|
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
// We pass the spread in a register, not on the stack.
|
Node* stack_arg_count = jsgraph()->Int32Constant(arg_count - 1);
|
node->InsertInput(zone(), 0, stub_code);
|
node->InsertInput(zone(), 2, stack_arg_count);
|
node->InsertInput(zone(), 3, node->InputAt(spread_index));
|
node->RemoveInput(spread_index + 1);
|
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
}
|
|
void JSGenericLowering::LowerJSCallRuntime(Node* node) {
|
const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
|
ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
|
}
|
|
void JSGenericLowering::LowerJSForInNext(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSForInPrepare(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSLoadMessage(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
|
void JSGenericLowering::LowerJSStoreMessage(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSLoadModule(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSStoreModule(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSGeneratorRestoreContext(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSGeneratorRestoreInputOrDebugPos(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
|
UNREACHABLE(); // Eliminated in typed lowering.
|
}
|
|
void JSGenericLowering::LowerJSStackCheck(Node* node) {
|
Node* effect = NodeProperties::GetEffectInput(node);
|
Node* control = NodeProperties::GetControlInput(node);
|
|
Node* limit = effect = graph()->NewNode(
|
machine()->Load(MachineType::Pointer()),
|
jsgraph()->ExternalConstant(
|
ExternalReference::address_of_stack_limit(isolate())),
|
jsgraph()->IntPtrConstant(0), effect, control);
|
Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
|
|
Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
|
Node* branch =
|
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
|
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
Node* etrue = effect;
|
|
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
NodeProperties::ReplaceControlInput(node, if_false);
|
NodeProperties::ReplaceEffectInput(node, effect);
|
Node* efalse = if_false = node;
|
|
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
|
|
// Wire the new diamond into the graph, {node} can still throw.
|
NodeProperties::ReplaceUses(node, node, ephi, merge, merge);
|
NodeProperties::ReplaceControlInput(merge, if_false, 1);
|
NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
|
|
// This iteration cuts out potential {IfSuccess} or {IfException} projection
|
// uses of the original node and places them inside the diamond, so that we
|
// can change the original {node} into the slow-path runtime call.
|
for (Edge edge : merge->use_edges()) {
|
if (!NodeProperties::IsControlEdge(edge)) continue;
|
if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
|
NodeProperties::ReplaceUses(edge.from(), nullptr, nullptr, merge);
|
NodeProperties::ReplaceControlInput(merge, edge.from(), 1);
|
edge.UpdateTo(node);
|
}
|
if (edge.from()->opcode() == IrOpcode::kIfException) {
|
NodeProperties::ReplaceEffectInput(edge.from(), node);
|
edge.UpdateTo(node);
|
}
|
}
|
|
// Turn the stack check into a runtime call.
|
ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
|
}
|
|
void JSGenericLowering::LowerJSDebugger(Node* node) {
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
Callable callable = CodeFactory::HandleDebuggerStatement(isolate());
|
ReplaceWithStubCall(node, callable, flags);
|
}
|
|
Zone* JSGenericLowering::zone() const { return graph()->zone(); }
|
|
|
Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
|
|
|
Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
|
|
|
CommonOperatorBuilder* JSGenericLowering::common() const {
|
return jsgraph()->common();
|
}
|
|
|
MachineOperatorBuilder* JSGenericLowering::machine() const {
|
return jsgraph()->machine();
|
}
|
|
} // namespace compiler
|
} // namespace internal
|
} // namespace v8
|