// 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);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
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,
}
// 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);
}
}
+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));
}
+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) \
}
+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>>( // --
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.
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);
// 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"
}
+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.
return ReduceJSLoadContext(node);
case IrOpcode::kJSStoreContext:
return ReduceJSStoreContext(node);
+ case IrOpcode::kJSCreateClosure:
+ return ReduceJSCreateClosure(node);
default:
break;
}
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,
#define JS_OBJECT_OP_LIST(V) \
V(JSCreate) \
+ V(JSCreateClosure) \
V(JSLoadProperty) \
V(JSLoadNamed) \
V(JSStoreProperty) \
}
+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())) {
// 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.
// 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"
#include "test/unittests/compiler/node-test-utils.h"
#include "testing/gmock-support.h"
+using testing::_;
using testing::BitEq;
using testing::IsNaN;
}
}
+
+// -----------------------------------------------------------------------------
+// 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