From d6e99a7f52cc8a9cdf0b956ce3836a9e1999bef1 Mon Sep 17 00:00:00 2001 From: mstarzinger Date: Mon, 27 Apr 2015 02:57:47 -0700 Subject: [PATCH] [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} --- src/compiler/ast-graph-builder.cc | 10 ++-- src/compiler/js-generic-lowering.cc | 14 +++++ src/compiler/js-intrinsic-lowering.cc | 64 ---------------------- src/compiler/js-intrinsic-lowering.h | 2 - src/compiler/js-operator.cc | 18 ++++++ src/compiler/js-operator.h | 2 + src/compiler/js-typed-lowering.cc | 62 +++++++++++++++++++++ src/compiler/js-typed-lowering.h | 2 + src/compiler/linkage.cc | 2 - src/compiler/opcodes.h | 2 + src/compiler/operator-properties.cc | 4 ++ src/compiler/typer.cc | 10 ++++ src/compiler/verifier.cc | 5 ++ .../compiler/js-intrinsic-lowering-unittest.cc | 52 ------------------ .../compiler/js-typed-lowering-unittest.cc | 48 ++++++++++++++++ 15 files changed, 171 insertions(+), 126 deletions(-) diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 03fee58..933f466 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -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()); diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 611b5c9..3ebb6bc 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -422,6 +422,20 @@ void JSGenericLowering::LowerJSCreateClosure(Node* node) { } +void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) { + int literal_flags = OpParameter(node->op()); + node->InsertInput(zone(), 3, jsgraph()->SmiConstant(literal_flags)); + ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral); +} + + +void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) { + int literal_flags = OpParameter(node->op()); + node->InsertInput(zone(), 3, jsgraph()->SmiConstant(literal_flags)); + ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral); +} + + void JSGenericLowering::LowerJSCreateCatchContext(Node* node) { Unique name = OpParameter>(node); node->InsertInput(zone(), 0, jsgraph()->HeapConstant(name)); diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc index c465720..b299e8b 100644 --- a/src/compiler/js-intrinsic-lowering.cc +++ b/src/compiler/js-intrinsic-lowering.cc @@ -6,10 +6,8 @@ #include -#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 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 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(); diff --git a/src/compiler/js-intrinsic-lowering.h b/src/compiler/js-intrinsic-lowering.h index 113e410..a0e773d 100644 --- a/src/compiler/js-intrinsic-lowering.h +++ b/src/compiler/js-intrinsic-lowering.h @@ -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); diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc index 91aa271..63a0d56 100644 --- a/src/compiler/js-operator.cc +++ b/src/compiler/js-operator.cc @@ -465,6 +465,24 @@ const Operator* JSOperatorBuilder::CreateClosure( } +const Operator* JSOperatorBuilder::CreateLiteralArray(int literal_flags) { + return new (zone()) Operator1( // -- + 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( // -- + IrOpcode::kJSCreateLiteralObject, Operator::kNoProperties, // opcode + "JSCreateLiteralObject", // name + 3, 1, 1, 1, 1, 2, // counts + literal_flags); // parameter +} + + const Operator* JSOperatorBuilder::CreateCatchContext( const Unique& name) { return new (zone()) Operator1>( // -- diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index bdb0c9c..739de6a 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -270,6 +270,8 @@ class JSOperatorBuilder final : public ZoneObject { const Operator* Create(); const Operator* CreateClosure(Handle 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); diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 554ef75..8e93d52 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -951,6 +951,64 @@ Reduction JSTypedLowering::ReduceJSCreateClosure(Node* node) { } +Reduction JSTypedLowering::ReduceJSCreateLiteralArray(Node* node) { + DCHECK_EQ(IrOpcode::kJSCreateLiteralArray, node->opcode()); + HeapObjectMatcher mconst(NodeProperties::GetValueInput(node, 2)); + int length = mconst.Value().handle()->length(); + int flags = OpParameter(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 mconst(NodeProperties::GetValueInput(node, 2)); + // Constants are pairs, see ObjectLiteral::properties_count(). + int length = mconst.Value().handle()->length() / 2; + int flags = OpParameter(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; } diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index 7f4b49e..855de8a 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -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, diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc index b4b8e2d..29d4388 100644 --- a/src/compiler/linkage.cc +++ b/src/compiler/linkage.cc @@ -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: diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 39f7cdb..e5b978a 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -107,6 +107,8 @@ #define JS_OBJECT_OP_LIST(V) \ V(JSCreate) \ V(JSCreateClosure) \ + V(JSCreateLiteralArray) \ + V(JSCreateLiteralObject) \ V(JSLoadProperty) \ V(JSLoadNamed) \ V(JSStoreProperty) \ diff --git a/src/compiler/operator-properties.cc b/src/compiler/operator-properties.cc index a87a172..a36caf5 100644 --- a/src/compiler/operator-properties.cc +++ b/src/compiler/operator-properties.cc @@ -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: diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 0e7d31c..6fd609f 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -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())) { diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index 733f8d7..238de2f 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -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. diff --git a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc index a9a59d5..bc34306 100644 --- a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -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" @@ -73,57 +72,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::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::CreateImmovable( - CodeFactory::FastCloneShallowObject(isolate(), 6).code())), - input0, input1, input2, input3, context, frame_state, effect, - control)); -} - - -// ----------------------------------------------------------------------------- // %_DoubleLo diff --git a/test/unittests/compiler/js-typed-lowering-unittest.cc b/test/unittests/compiler/js-typed-lowering-unittest.cc index e269db0..aa4d81c 100644 --- a/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -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::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::CreateImmovable( + CodeFactory::FastCloneShallowObject(isolate(), 6).code())), + input0, input1, input2, _, context, frame_state, effect, control)); +} + } // namespace compiler } // namespace internal } // namespace v8 -- 2.7.4