Commit d6e99a7f authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Introduce explicit JSCreateLiteral[Array|Object].

This uses explicit operators instead of intrinsic runtime calls to
create literals froms boilerplates. It allows for easier access of
static parameters and syncs it with other allocating operators.

R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/1104453006

Cr-Commit-Position: refs/heads/master@{#28062}
parent ecf499ef
......@@ -1660,10 +1660,9 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_properties());
Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
const Operator* op =
javascript()->CallRuntime(Runtime::kInlineCreateObjectLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
javascript()->CreateLiteralObject(expr->ComputeFlags(true));
Node* literal = NewNode(op, literals_array, literal_index, constants);
PrepareFrameState(literal, expr->CreateLiteralId(),
OutputFrameStateCombine::Push());
......@@ -1852,10 +1851,9 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_elements());
Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
const Operator* op =
javascript()->CallRuntime(Runtime::kInlineCreateArrayLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
javascript()->CreateLiteralArray(expr->ComputeFlags(true));
Node* literal = NewNode(op, literals_array, literal_index, constants);
PrepareFrameState(literal, expr->CreateLiteralId(),
OutputFrameStateCombine::Push());
......
......@@ -422,6 +422,20 @@ void JSGenericLowering::LowerJSCreateClosure(Node* node) {
}
void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
int literal_flags = OpParameter<int>(node->op());
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(literal_flags));
ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
}
void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
int literal_flags = OpParameter<int>(node->op());
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(literal_flags));
ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
}
void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
Unique<String> name = OpParameter<Unique<String>>(node);
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(name));
......
......@@ -6,10 +6,8 @@
#include <stack>
#include "src/code-factory.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
......@@ -30,10 +28,6 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
switch (f->function_id) {
case Runtime::kInlineConstructDouble:
return ReduceConstructDouble(node);
case Runtime::kInlineCreateArrayLiteral:
return ReduceCreateArrayLiteral(node);
case Runtime::kInlineCreateObjectLiteral:
return ReduceCreateObjectLiteral(node);
case Runtime::kInlineDeoptimizeNow:
return ReduceDeoptimizeNow(node);
case Runtime::kInlineDoubleHi:
......@@ -100,64 +94,6 @@ Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
}
Reduction JSIntrinsicLowering::ReduceCreateArrayLiteral(Node* node) {
HeapObjectMatcher<FixedArray> mconst(NodeProperties::GetValueInput(node, 2));
NumberMatcher mflags(NodeProperties::GetValueInput(node, 3));
int length = mconst.Value().handle()->length();
int flags = FastD2I(mflags.Value());
// Use the FastCloneShallowArrayStub only for shallow boilerplates up to the
// initial length limit for arrays with "fast" elements kind.
if ((flags & ArrayLiteral::kShallowElements) != 0 &&
length < JSObject::kInitialMaxFastElementArray) {
Isolate* isolate = jsgraph()->isolate();
Callable callable = CodeFactory::FastCloneShallowArray(isolate);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate, graph()->zone(), callable.descriptor(), 0,
(OperatorProperties::GetFrameStateInputCount(node->op()) != 0)
? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags);
const Operator* new_op = common()->Call(desc);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->RemoveInput(3); // Remove flags input from node.
node->InsertInput(graph()->zone(), 0, stub_code);
node->set_op(new_op);
return Changed(node);
}
return NoChange();
}
Reduction JSIntrinsicLowering::ReduceCreateObjectLiteral(Node* node) {
HeapObjectMatcher<FixedArray> mconst(NodeProperties::GetValueInput(node, 2));
NumberMatcher mflags(NodeProperties::GetValueInput(node, 3));
// Constants are pairs, see ObjectLiteral::properties_count().
int length = mconst.Value().handle()->length() / 2;
int flags = FastD2I(mflags.Value());
// Use the FastCloneShallowObjectStub only for shallow boilerplates without
// elements up to the number of properties that the stubs can handle.
if ((flags & ObjectLiteral::kShallowProperties) != 0 &&
length <= FastCloneShallowObjectStub::kMaximumClonedProperties) {
Isolate* isolate = jsgraph()->isolate();
Callable callable = CodeFactory::FastCloneShallowObject(isolate, length);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate, graph()->zone(), callable.descriptor(), 0,
(OperatorProperties::GetFrameStateInputCount(node->op()) != 0)
? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags);
const Operator* new_op = common()->Call(desc);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->InsertInput(graph()->zone(), 0, stub_code);
node->set_op(new_op);
return Changed(node);
}
return NoChange();
}
Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
// TODO(jarin): This should not depend on the global flag.
if (!FLAG_turbo_deoptimization) return NoChange();
......
......@@ -29,8 +29,6 @@ class JSIntrinsicLowering final : public Reducer {
private:
Reduction ReduceConstructDouble(Node* node);
Reduction ReduceCreateArrayLiteral(Node* node);
Reduction ReduceCreateObjectLiteral(Node* node);
Reduction ReduceDeoptimizeNow(Node* node);
Reduction ReduceDoubleHi(Node* node);
Reduction ReduceDoubleLo(Node* node);
......
......@@ -465,6 +465,24 @@ const Operator* JSOperatorBuilder::CreateClosure(
}
const Operator* JSOperatorBuilder::CreateLiteralArray(int literal_flags) {
return new (zone()) Operator1<int>( // --
IrOpcode::kJSCreateLiteralArray, Operator::kNoProperties, // opcode
"JSCreateLiteralArray", // name
3, 1, 1, 1, 1, 2, // counts
literal_flags); // parameter
}
const Operator* JSOperatorBuilder::CreateLiteralObject(int literal_flags) {
return new (zone()) Operator1<int>( // --
IrOpcode::kJSCreateLiteralObject, Operator::kNoProperties, // opcode
"JSCreateLiteralObject", // name
3, 1, 1, 1, 1, 2, // counts
literal_flags); // parameter
}
const Operator* JSOperatorBuilder::CreateCatchContext(
const Unique<String>& name) {
return new (zone()) Operator1<Unique<String>>( // --
......
......@@ -270,6 +270,8 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* Create();
const Operator* CreateClosure(Handle<SharedFunctionInfo> shared_info,
PretenureFlag pretenure);
const Operator* CreateLiteralArray(int literal_flags);
const Operator* CreateLiteralObject(int literal_flags);
const Operator* CallFunction(size_t arity, CallFunctionFlags flags);
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
......
......@@ -951,6 +951,64 @@ Reduction JSTypedLowering::ReduceJSCreateClosure(Node* node) {
}
Reduction JSTypedLowering::ReduceJSCreateLiteralArray(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateLiteralArray, node->opcode());
HeapObjectMatcher<FixedArray> mconst(NodeProperties::GetValueInput(node, 2));
int length = mconst.Value().handle()->length();
int flags = OpParameter<int>(node->op());
// Use the FastCloneShallowArrayStub only for shallow boilerplates up to the
// initial length limit for arrays with "fast" elements kind.
if ((flags & ArrayLiteral::kShallowElements) != 0 &&
length < JSObject::kInitialMaxFastElementArray) {
Isolate* isolate = jsgraph()->isolate();
Callable callable = CodeFactory::FastCloneShallowArray(isolate);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate, graph()->zone(), callable.descriptor(), 0,
(OperatorProperties::GetFrameStateInputCount(node->op()) != 0)
? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags);
const Operator* new_op = common()->Call(desc);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->InsertInput(graph()->zone(), 0, stub_code);
node->set_op(new_op);
return Changed(node);
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSCreateLiteralObject(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateLiteralObject, node->opcode());
HeapObjectMatcher<FixedArray> mconst(NodeProperties::GetValueInput(node, 2));
// Constants are pairs, see ObjectLiteral::properties_count().
int length = mconst.Value().handle()->length() / 2;
int flags = OpParameter<int>(node->op());
// Use the FastCloneShallowObjectStub only for shallow boilerplates without
// elements up to the number of properties that the stubs can handle.
if ((flags & ObjectLiteral::kShallowProperties) != 0 &&
length <= FastCloneShallowObjectStub::kMaximumClonedProperties) {
Isolate* isolate = jsgraph()->isolate();
Callable callable = CodeFactory::FastCloneShallowObject(isolate, length);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate, graph()->zone(), callable.descriptor(), 0,
(OperatorProperties::GetFrameStateInputCount(node->op()) != 0)
? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags);
const Operator* new_op = common()->Call(desc);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(flags));
node->InsertInput(graph()->zone(), 0, stub_code);
node->set_op(new_op);
return Changed(node);
}
return NoChange();
}
Reduction JSTypedLowering::Reduce(Node* node) {
// Check if the output type is a singleton. In that case we already know the
// result value and can simply replace the node if it's eliminable.
......@@ -1039,6 +1097,10 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSStoreContext(node);
case IrOpcode::kJSCreateClosure:
return ReduceJSCreateClosure(node);
case IrOpcode::kJSCreateLiteralArray:
return ReduceJSCreateLiteralArray(node);
case IrOpcode::kJSCreateLiteralObject:
return ReduceJSCreateLiteralObject(node);
default:
break;
}
......
......@@ -55,6 +55,8 @@ class JSTypedLowering final : public Reducer {
Reduction ReduceJSToStringInput(Node* input);
Reduction ReduceJSToString(Node* node);
Reduction ReduceJSCreateClosure(Node* node);
Reduction ReduceJSCreateLiteralArray(Node* node);
Reduction ReduceJSCreateLiteralObject(Node* node);
Reduction ReduceNumberBinop(Node* node, const Operator* numberOp);
Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
......
......@@ -123,8 +123,6 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
return false;
case Runtime::kInlineArguments:
case Runtime::kInlineCallFunction:
case Runtime::kInlineCreateArrayLiteral:
case Runtime::kInlineCreateObjectLiteral:
case Runtime::kInlineDateField:
case Runtime::kInlineDeoptimizeNow:
case Runtime::kInlineGetPrototype:
......
......@@ -107,6 +107,8 @@
#define JS_OBJECT_OP_LIST(V) \
V(JSCreate) \
V(JSCreateClosure) \
V(JSCreateLiteralArray) \
V(JSCreateLiteralObject) \
V(JSLoadProperty) \
V(JSLoadNamed) \
V(JSStoreProperty) \
......
......@@ -48,6 +48,10 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSNotEqual:
// Object operations
case IrOpcode::kJSCreateLiteralArray:
case IrOpcode::kJSCreateLiteralObject:
// Context operations
case IrOpcode::kJSCreateScriptContext:
case IrOpcode::kJSCreateWithContext:
......
......@@ -1316,6 +1316,16 @@ Bounds Typer::Visitor::TypeJSCreateClosure(Node* node) {
}
Bounds Typer::Visitor::TypeJSCreateLiteralArray(Node* node) {
return Bounds(Type::None(), Type::OtherObject());
}
Bounds Typer::Visitor::TypeJSCreateLiteralObject(Node* node) {
return Bounds(Type::None(), Type::OtherObject());
}
Type* Typer::Visitor::JSLoadPropertyTyper(Type* object, Type* name, Typer* t) {
// TODO(rossberg): Use range types and sized array types to filter undefined.
if (object->IsArray() && name->Is(Type::Integral32())) {
......
......@@ -496,6 +496,11 @@ void Verifier::Visitor::Check(Node* node) {
// Type is Function.
CheckUpperIs(node, Type::OtherObject());
break;
case IrOpcode::kJSCreateLiteralArray:
case IrOpcode::kJSCreateLiteralObject:
// Type is OtherObject.
CheckUpperIs(node, Type::OtherObject());
break;
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSLoadNamed:
// Type can be anything.
......
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/code-factory.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/diamond.h"
#include "src/compiler/js-graph.h"
......@@ -72,57 +71,6 @@ TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) {
}
// -----------------------------------------------------------------------------
// %_CreateArrayLiteral
TEST_F(JSIntrinsicLoweringTest, InlineCreateArrayLiteral) {
Node* const input0 = Parameter(0);
Node* const input1 = Parameter(1);
Node* const input2 = HeapConstant(factory()->NewFixedArray(12));
Node* const input3 = NumberConstant(ArrayLiteral::kShallowElements);
Node* const context = Parameter(2);
Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode(
javascript()->CallRuntime(Runtime::kInlineCreateArrayLiteral, 4), input0,
input1, input2, input3, context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
CodeFactory::FastCloneShallowArray(isolate()).code())),
input0, input1, input2, context, frame_state, effect, control));
}
// -----------------------------------------------------------------------------
// %_CreateObjectLiteral
TEST_F(JSIntrinsicLoweringTest, InlineCreateObjectLiteral) {
Node* const input0 = Parameter(0);
Node* const input1 = Parameter(1);
Node* const input2 = HeapConstant(factory()->NewFixedArray(2 * 6));
Node* const input3 = NumberConstant(ObjectLiteral::kShallowProperties);
Node* const context = Parameter(2);
Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode(
javascript()->CallRuntime(Runtime::kInlineCreateObjectLiteral, 4), input0,
input1, input2, input3, context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
CodeFactory::FastCloneShallowObject(isolate(), 6).code())),
input0, input1, input2, input3, context, frame_state, effect,
control));
}
// -----------------------------------------------------------------------------
// %_DoubleLo
......
......@@ -906,6 +906,54 @@ TEST_F(JSTypedLoweringTest, JSCreateClosure) {
effect, control));
}
// -----------------------------------------------------------------------------
// JSCreateLiteralArray
TEST_F(JSTypedLoweringTest, JSCreateLiteralArray) {
Node* const input0 = Parameter(0);
Node* const input1 = Parameter(1);
Node* const input2 = HeapConstant(factory()->NewFixedArray(12));
Node* const context = UndefinedConstant();
Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode(
javascript()->CreateLiteralArray(ArrayLiteral::kShallowElements), input0,
input1, input2, context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
CodeFactory::FastCloneShallowArray(isolate()).code())),
input0, input1, input2, context, frame_state, effect, control));
}
// -----------------------------------------------------------------------------
// JSCreateLiteralObject
TEST_F(JSTypedLoweringTest, JSCreateLiteralObject) {
Node* const input0 = Parameter(0);
Node* const input1 = Parameter(1);
Node* const input2 = HeapConstant(factory()->NewFixedArray(2 * 6));
Node* const context = UndefinedConstant();
Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode(
javascript()->CreateLiteralObject(ObjectLiteral::kShallowProperties),
input0, input1, input2, context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
CodeFactory::FastCloneShallowObject(isolate(), 6).code())),
input0, input1, input2, _, context, frame_state, effect, control));
}
} // namespace compiler
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment