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

[turbofan] Use FastNewClosureStub if possible.

This introduces a JSCreateClosure operator which can be lowered by the
typed pipeline to the aforementioned stub. It also allows for further
optimizations of closure creation.

R=titzer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#28058}
parent aae4a62d
......@@ -158,6 +158,15 @@ Callable CodeFactory::FastCloneShallowObject(Isolate* isolate, int length) {
}
// static
Callable CodeFactory::FastNewClosure(Isolate* isolate,
LanguageMode language_mode,
FunctionKind kind) {
FastNewClosureStub stub(isolate, language_mode, kind);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::AllocateHeapNumber(Isolate* isolate) {
AllocateHeapNumberStub stub(isolate);
......
......@@ -69,6 +69,9 @@ class CodeFactory final {
static Callable FastCloneShallowArray(Isolate* isolate);
static Callable FastCloneShallowObject(Isolate* isolate, int length);
static Callable FastNewClosure(Isolate* isolate, LanguageMode language_mode,
FunctionKind kind);
static Callable AllocateHeapNumber(Isolate* isolate);
static Callable CallFunction(Isolate* isolate, int argc,
......
......@@ -1476,10 +1476,9 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
}
// Create node to instantiate a new closure.
Node* info = jsgraph()->Constant(shared_info);
Node* pretenure = jsgraph()->BooleanConstant(expr->pretenure());
const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3);
Node* value = NewNode(op, context, info, pretenure);
PretenureFlag pretenure = expr->pretenure() ? TENURED : NOT_TENURED;
const Operator* op = javascript()->CreateClosure(shared_info, pretenure);
Node* value = NewNode(op, context);
ast_context()->ProduceValue(value);
}
......
......@@ -414,6 +414,14 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) {
}
void JSGenericLowering::LowerJSCreateClosure(Node* node) {
CreateClosureParameters p = CreateClosureParametersOf(node->op());
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.shared_info()));
node->InsertInput(zone(), 2, jsgraph()->BooleanConstant(p.pretenure()));
ReplaceWithRuntimeCall(node, Runtime::kNewClosure);
}
void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
Unique<String> name = OpParameter<Unique<String>>(node);
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(name));
......
......@@ -208,6 +208,37 @@ const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
}
bool operator==(CreateClosureParameters const& lhs,
CreateClosureParameters const& rhs) {
return lhs.pretenure() == rhs.pretenure() &&
lhs.shared_info().is_identical_to(rhs.shared_info());
}
bool operator!=(CreateClosureParameters const& lhs,
CreateClosureParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(CreateClosureParameters const& p) {
// TODO(mstarzinger): Include hash of the SharedFunctionInfo here.
base::hash<PretenureFlag> h;
return h(p.pretenure());
}
std::ostream& operator<<(std::ostream& os, CreateClosureParameters const& p) {
return os << p.pretenure() << ", " << Brief(*p.shared_info());
}
const CreateClosureParameters& CreateClosureParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kJSCreateClosure, op->opcode());
return OpParameter<CreateClosureParameters>(op);
}
#define CACHED_OP_LIST(V) \
V(Equal, Operator::kNoProperties, 2, 1) \
V(NotEqual, Operator::kNoProperties, 2, 1) \
......@@ -437,6 +468,17 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
}
const Operator* JSOperatorBuilder::CreateClosure(
Handle<SharedFunctionInfo> shared_info, PretenureFlag pretenure) {
CreateClosureParameters parameters(shared_info, pretenure);
return new (zone()) Operator1<CreateClosureParameters>( // --
IrOpcode::kJSCreateClosure, Operator::kNoThrow, // opcode
"JSCreateClosure", // name
1, 1, 1, 1, 1, 0, // counts
parameters); // parameter
}
const Operator* JSOperatorBuilder::CreateCatchContext(
const Unique<String>& name) {
return new (zone()) Operator1<Unique<String>>( // --
......
......@@ -206,6 +206,32 @@ std::ostream& operator<<(std::ostream&, StoreNamedParameters const&);
const StoreNamedParameters& StoreNamedParametersOf(const Operator* op);
// Defines shared information for the closure that should be created. This is
// used as a parameter by JSCreateClosure operators.
class CreateClosureParameters final {
public:
CreateClosureParameters(Handle<SharedFunctionInfo> shared_info,
PretenureFlag pretenure)
: shared_info_(shared_info), pretenure_(pretenure) {}
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
PretenureFlag pretenure() const { return pretenure_; }
private:
const Handle<SharedFunctionInfo> shared_info_;
const PretenureFlag pretenure_;
};
bool operator==(CreateClosureParameters const&, CreateClosureParameters const&);
bool operator!=(CreateClosureParameters const&, CreateClosureParameters const&);
size_t hash_value(CreateClosureParameters const&);
std::ostream& operator<<(std::ostream&, CreateClosureParameters const&);
const CreateClosureParameters& CreateClosureParametersOf(const Operator* op);
// Interface for building JavaScript-level operators, e.g. directly from the
// AST. Most operators have no parameters, thus can be globally shared for all
// graphs.
......@@ -242,6 +268,8 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* Yield();
const Operator* Create();
const Operator* CreateClosure(Handle<SharedFunctionInfo> shared_info,
PretenureFlag pretenure);
const Operator* CallFunction(size_t arity, CallFunctionFlags flags);
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
......
......@@ -2,9 +2,11 @@
// 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/js-graph.h"
#include "src/compiler/js-typed-lowering.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
......@@ -923,6 +925,32 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
}
Reduction JSTypedLowering::ReduceJSCreateClosure(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode());
CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
Handle<SharedFunctionInfo> shared = p.shared_info();
// Use the FastNewClosureStub that allocates in new space only for nested
// functions that don't need literals cloning.
if (p.pretenure() == NOT_TENURED && shared->num_literals() == 0) {
Isolate* isolate = jsgraph()->isolate();
Callable callable = CodeFactory::FastNewClosure(
isolate, shared->language_mode(), shared->kind());
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate, graph()->zone(), callable.descriptor(), 0,
CallDescriptor::kNoFlags);
const Operator* new_op = common()->Call(desc);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->ReplaceInput(0, jsgraph()->HeapConstant(shared));
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.
......@@ -1009,6 +1037,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSLoadContext(node);
case IrOpcode::kJSStoreContext:
return ReduceJSStoreContext(node);
case IrOpcode::kJSCreateClosure:
return ReduceJSCreateClosure(node);
default:
break;
}
......
......@@ -54,6 +54,7 @@ class JSTypedLowering final : public Reducer {
Reduction ReduceJSToNumber(Node* node);
Reduction ReduceJSToStringInput(Node* input);
Reduction ReduceJSToString(Node* node);
Reduction ReduceJSCreateClosure(Node* node);
Reduction ReduceNumberBinop(Node* node, const Operator* numberOp);
Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
......
......@@ -106,6 +106,7 @@
#define JS_OBJECT_OP_LIST(V) \
V(JSCreate) \
V(JSCreateClosure) \
V(JSLoadProperty) \
V(JSLoadNamed) \
V(JSStoreProperty) \
......
......@@ -1311,6 +1311,11 @@ Bounds Typer::Visitor::TypeJSCreate(Node* node) {
}
Bounds Typer::Visitor::TypeJSCreateClosure(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())) {
......
......@@ -492,6 +492,10 @@ void Verifier::Visitor::Check(Node* node) {
// Type is Object.
CheckUpperIs(node, Type::Object());
break;
case IrOpcode::kJSCreateClosure:
// Type is Function.
CheckUpperIs(node, Type::OtherObject());
break;
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSLoadNamed:
// Type can be anything.
......
......@@ -2,6 +2,7 @@
// 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/js-graph.h"
#include "src/compiler/js-operator.h"
......@@ -14,6 +15,7 @@
#include "test/unittests/compiler/node-test-utils.h"
#include "testing/gmock-support.h"
using testing::_;
using testing::BitEq;
using testing::IsNaN;
......@@ -880,6 +882,30 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
}
}
// -----------------------------------------------------------------------------
// JSCreateClosure
TEST_F(JSTypedLoweringTest, JSCreateClosure) {
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
Node* const control = graph()->start();
Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
Reduction r =
Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED),
context, context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsCall(_,
IsHeapConstant(Unique<HeapObject>::CreateImmovable(
CodeFactory::FastNewClosure(isolate(), shared->language_mode(),
shared->kind()).code())),
IsHeapConstant(Unique<HeapObject>::CreateImmovable(shared)),
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