[turbofan] Some javascript operators are globally shared singletons.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Tue, 30 Sep 2014 10:42:44 +0000 (10:42 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Tue, 30 Sep 2014 10:42:44 +0000 (10:42 +0000)
Also cleanup the interface, and make the parameter class/accessors
explicit to work-around the type-unsafety of OpParameter<T>.

TEST=compiler-unittests,cctest,mjsunit
R=mstarzinger@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24322 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

19 files changed:
BUILD.gn
src/compiler/ast-graph-builder.cc
src/compiler/ast-graph-builder.h
src/compiler/change-lowering.cc
src/compiler/compiler.gyp
src/compiler/js-builtin-reducer-unittest.cc
src/compiler/js-context-specialization.cc
src/compiler/js-generic-lowering.cc
src/compiler/js-generic-lowering.h
src/compiler/js-operator-unittest.cc [new file with mode: 0644]
src/compiler/js-operator.cc [new file with mode: 0644]
src/compiler/js-operator.h
src/compiler/machine-operator-reducer.cc
src/compiler/operator-properties-inl.h
src/compiler/typer.cc
src/runtime/runtime.h
test/cctest/compiler/test-js-context-specialization.cc
test/cctest/compiler/test-machine-operator-reducer.cc
tools/gyp/v8.gyp

index 5ba74eb..bfc7683 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -520,6 +520,7 @@ source_set("v8_base") {
     "src/compiler/js-graph.h",
     "src/compiler/js-inlining.cc",
     "src/compiler/js-inlining.h",
+    "src/compiler/js-operator.cc",
     "src/compiler/js-operator.h",
     "src/compiler/js-typed-lowering.cc",
     "src/compiler/js-typed-lowering.h",
index 01cde01..d33b05a 100644 (file)
@@ -75,7 +75,7 @@ bool AstGraphBuilder::CreateGraph() {
 
   // Emit tracing call if requested to do so.
   if (FLAG_trace) {
-    NewNode(javascript()->Runtime(Runtime::kTraceEnter, 0));
+    NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
   }
 
   // Visit implicit declaration of the function name.
@@ -87,7 +87,7 @@ bool AstGraphBuilder::CreateGraph() {
   VisitDeclarations(scope->declarations());
 
   // TODO(mstarzinger): This should do an inlined stack check.
-  Node* node = NewNode(javascript()->Runtime(Runtime::kStackGuard, 0));
+  Node* node = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0));
   PrepareFrameState(node, BailoutId::FunctionEntry());
 
   // Visit statements in the function body.
@@ -98,7 +98,7 @@ bool AstGraphBuilder::CreateGraph() {
   if (FLAG_trace) {
     // TODO(mstarzinger): Only traces implicit return.
     Node* return_value = jsgraph()->UndefinedConstant();
-    NewNode(javascript()->Runtime(Runtime::kTraceExit, 1), return_value);
+    NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value);
   }
 
   // Return 'undefined' in case we can fall off the end.
@@ -643,20 +643,20 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
     // TODO(dcarney): should do a fast enum cache check here to skip runtime.
     environment()->Push(obj);
     Node* cache_type = ProcessArguments(
-        javascript()->Runtime(Runtime::kGetPropertyNamesFast, 1), 1);
+        javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), 1);
     // TODO(dcarney): these next runtime calls should be removed in favour of
     //                a few simplified instructions.
     environment()->Push(obj);
     environment()->Push(cache_type);
     Node* cache_pair =
-        ProcessArguments(javascript()->Runtime(Runtime::kForInInit, 2), 2);
+        ProcessArguments(javascript()->CallRuntime(Runtime::kForInInit, 2), 2);
     // cache_type may have been replaced.
     Node* cache_array = NewNode(common()->Projection(0), cache_pair);
     cache_type = NewNode(common()->Projection(1), cache_pair);
     environment()->Push(cache_type);
     environment()->Push(cache_array);
     Node* cache_length = ProcessArguments(
-        javascript()->Runtime(Runtime::kForInCacheArrayLength, 2), 2);
+        javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2), 2);
     {
       // TODO(dcarney): this check is actually supposed to be for the
       //                empty enum case only.
@@ -692,8 +692,8 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
         environment()->Push(cache_array);
         environment()->Push(cache_type);
         environment()->Push(index);
-        Node* pair =
-            ProcessArguments(javascript()->Runtime(Runtime::kForInNext, 4), 4);
+        Node* pair = ProcessArguments(
+            javascript()->CallRuntime(Runtime::kForInNext, 4), 4);
         Node* value = NewNode(common()->Projection(0), pair);
         Node* should_filter = NewNode(common()->Projection(1), pair);
         environment()->Push(value);
@@ -719,7 +719,7 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
           // result is either the string key or Smi(0) indicating the property
           // is gone.
           Node* res = ProcessArguments(
-              javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3);
+              javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), 3);
           // TODO(jarin): provide real bailout id.
           PrepareFrameState(res, BailoutId::None());
           Node* property_missing = NewNode(javascript()->StrictEqual(), res,
@@ -785,7 +785,7 @@ void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
 
 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
   // TODO(turbofan): Do we really need a separate reloc-info for this?
-  Node* node = NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0));
+  Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
   PrepareFrameState(node, stmt->DebugBreakId());
 }
 
@@ -806,7 +806,7 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
   Node* info = jsgraph()->Constant(shared_info);
   Node* pretenure = expr->pretenure() ? jsgraph()->TrueConstant()
                                       : jsgraph()->FalseConstant();
-  const Operator* op = javascript()->Runtime(Runtime::kNewClosure, 3);
+  const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3);
   Node* value = NewNode(op, context, info, pretenure);
   ast_context()->ProduceValue(value);
 }
@@ -859,7 +859,7 @@ void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
   Node* pattern = jsgraph()->Constant(expr->pattern());
   Node* flags = jsgraph()->Constant(expr->flags());
   const Operator* op =
-      javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
+      javascript()->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
   Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
   PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(literal);
@@ -876,7 +876,8 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
   Node* literal_index = jsgraph()->Constant(expr->literal_index());
   Node* constants = jsgraph()->Constant(expr->constant_properties());
   Node* flags = jsgraph()->Constant(expr->ComputeFlags());
-  const Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4);
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4);
   Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
 
   // The object is expected on the operand stack during computation of the
@@ -925,7 +926,8 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
         Node* receiver = environment()->Pop();
         if (property->emit_store()) {
           Node* strict = jsgraph()->Constant(SLOPPY);
-          const Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4);
+          const Operator* op =
+              javascript()->CallRuntime(Runtime::kSetProperty, 4);
           NewNode(op, receiver, key, value, strict);
         }
         break;
@@ -936,7 +938,8 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
         Node* value = environment()->Pop();
         Node* receiver = environment()->Pop();
         if (property->emit_store()) {
-          const Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2);
+          const Operator* op =
+              javascript()->CallRuntime(Runtime::kSetPrototype, 2);
           NewNode(op, receiver, value);
         }
         break;
@@ -962,14 +965,15 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
     Node* name = environment()->Pop();
     Node* attr = jsgraph()->Constant(NONE);
     const Operator* op =
-        javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
     Node* call = NewNode(op, literal, name, getter, setter, attr);
     PrepareFrameState(call, it->first->id());
   }
 
   // Transform literals that contain functions to fast properties.
   if (expr->has_function()) {
-    const Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1);
+    const Operator* op =
+        javascript()->CallRuntime(Runtime::kToFastProperties, 1);
     NewNode(op, literal);
   }
 
@@ -987,7 +991,8 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
   Node* literal_index = jsgraph()->Constant(expr->literal_index());
   Node* constants = jsgraph()->Constant(expr->constant_elements());
   Node* flags = jsgraph()->Constant(expr->ComputeFlags());
-  const Operator* op = javascript()->Runtime(Runtime::kCreateArrayLiteral, 4);
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4);
   Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
 
   // The array and the literal index are both expected on the operand stack
@@ -1166,7 +1171,7 @@ void AstGraphBuilder::VisitYield(Yield* expr) {
 void AstGraphBuilder::VisitThrow(Throw* expr) {
   VisitForValue(expr->exception());
   Node* exception = environment()->Pop();
-  const Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
+  const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
   Node* value = NewNode(op, exception);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1213,7 +1218,8 @@ void AstGraphBuilder::VisitCall(Call* expr) {
       Variable* variable = callee->AsVariableProxy()->var();
       DCHECK(variable->location() == Variable::LOOKUP);
       Node* name = jsgraph()->Constant(variable->name());
-      const Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2);
+      const Operator* op =
+          javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
       Node* pair = NewNode(op, current_context(), name);
       callee_value = NewNode(common()->Projection(0), pair);
       receiver_value = NewNode(common()->Projection(1), pair);
@@ -1278,7 +1284,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
     Node* strict = jsgraph()->Constant(strict_mode());
     Node* position = jsgraph()->Constant(info()->scope()->start_position());
     const Operator* op =
-        javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5);
+        javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
     Node* pair = NewNode(op, callee, source, receiver, strict, position);
     PrepareFrameState(pair, expr->EvalOrLookupId(),
                       OutputFrameStateCombine::PokeAt(arg_count + 1));
@@ -1291,7 +1297,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
   }
 
   // Create node to perform the function call.
-  const Operator* call = javascript()->Call(args->length() + 2, flags);
+  const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
   Node* value = ProcessArguments(call, args->length() + 2);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1306,7 +1312,7 @@ void AstGraphBuilder::VisitCallNew(CallNew* expr) {
   VisitForValues(args);
 
   // Create node to perform the construct call.
-  const Operator* call = javascript()->CallNew(args->length() + 1);
+  const Operator* call = javascript()->CallConstruct(args->length() + 1);
   Node* value = ProcessArguments(call, args->length() + 1);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1334,7 +1340,7 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
   VisitForValues(args);
 
   // Create node to perform the JS runtime call.
-  const Operator* call = javascript()->Call(args->length() + 2, flags);
+  const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
   Node* value = ProcessArguments(call, args->length() + 2);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1357,7 +1363,7 @@ void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
 
   // Create node to perform the runtime call.
   Runtime::FunctionId functionId = function->function_id;
-  const Operator* call = javascript()->Runtime(functionId, args->length());
+  const Operator* call = javascript()->CallRuntime(functionId, args->length());
   Node* value = ProcessArguments(call, args->length());
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1571,7 +1577,7 @@ void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
                       DeclareGlobalsStrictMode::encode(strict_mode());
   Node* flags = jsgraph()->Constant(encoded_flags);
   Node* pairs = jsgraph()->Constant(data);
-  const Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3);
+  const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals, 3);
   NewNode(op, current_context(), pairs, flags);
   globals()->Rewind(0);
 }
@@ -1680,6 +1686,11 @@ void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
 }
 
 
+StrictMode AstGraphBuilder::strict_mode() const {
+  return info()->strict_mode();
+}
+
+
 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
   DCHECK(environment()->stack_height() >= arity);
   Node** all = info()->zone()->NewArray<Node*>(arity);
@@ -1724,7 +1735,7 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
 
   // Allocate and initialize a new arguments object.
   Node* callee = GetFunctionClosure();
-  const Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1);
+  const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1);
   Node* object = NewNode(op, callee);
 
   // Assign the object to the arguments variable.
@@ -1831,7 +1842,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
           (contextual_mode == CONTEXTUAL)
               ? Runtime::kLoadLookupSlot
               : Runtime::kLoadLookupSlotNoReferenceError;
-      const Operator* op = javascript()->Runtime(function_id, 2);
+      const Operator* op = javascript()->CallRuntime(function_id, 2);
       Node* pair = NewNode(op, current_context(), name);
       PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
       return NewNode(common()->Projection(0), pair);
@@ -1864,7 +1875,8 @@ Node* AstGraphBuilder::BuildVariableDelete(
     case Variable::LOOKUP: {
       // Dynamic lookup of context variable (anywhere in the chain).
       Node* name = jsgraph()->Constant(variable->name());
-      const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
+      const Operator* op =
+          javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
       Node* result = NewNode(op, current_context(), name);
       PrepareFrameState(result, bailout_id, state_combine);
       return result;
@@ -1950,7 +1962,8 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
       Node* strict = jsgraph()->Constant(strict_mode());
       // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
       // initializations of const declarations.
-      const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
+      const Operator* op =
+          javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
       Node* store = NewNode(op, value, current_context(), name, strict);
       PrepareFrameState(store, bailout_id);
       return store;
@@ -1995,7 +2008,8 @@ Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
                                                 BailoutId bailout_id) {
   // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
   Node* variable_name = jsgraph()->Constant(variable->name());
-  const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kThrowReferenceError, 1);
   Node* call = NewNode(op, variable_name);
   PrepareFrameState(call, bailout_id);
   return call;
index b622355..feded98 100644 (file)
@@ -131,8 +131,8 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
   SetOncePointer<Node> function_closure_;
   SetOncePointer<Node> function_context_;
 
-  CompilationInfo* info() { return info_; }
-  StrictMode strict_mode() { return info()->strict_mode(); }
+  CompilationInfo* info() const { return info_; }
+  inline StrictMode strict_mode() const;
   JSGraph* jsgraph() { return jsgraph_; }
   JSOperatorBuilder* javascript() { return jsgraph_->javascript(); }
   ZoneList<Handle<Object> >* globals() { return &globals_; }
index b13db4c..5b66d55 100644 (file)
@@ -3,9 +3,10 @@
 // found in the LICENSE file.
 
 #include "src/compiler/change-lowering.h"
-#include "src/compiler/machine-operator.h"
 
 #include "src/compiler/js-graph.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/machine-operator.h"
 
 namespace v8 {
 namespace internal {
index ec5ec28..2a831d8 100644 (file)
@@ -27,6 +27,7 @@
         'instruction-selector-unittest.cc',
         'instruction-selector-unittest.h',
         'js-builtin-reducer-unittest.cc',
+        'js-operator-unittest.cc',
         'machine-operator-reducer-unittest.cc',
         'machine-operator-unittest.cc',
         'simplified-operator-reducer-unittest.cc',
index 5177d8d..22311a6 100644 (file)
@@ -69,8 +69,9 @@ TEST_F(JSBuiltinReducerTest, MathAbs) {
   TRACED_FOREACH(Type*, t0, kNumberTypes) {
     Node* p0 = Parameter(t0, 0);
     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-    Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
-                                  fun, UndefinedConstant(), p0);
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
     Reduction r = Reduce(call);
 
     if (t0->Is(Type::Unsigned32())) {
@@ -102,8 +103,9 @@ TEST_F(JSBuiltinReducerTest, MathSqrt) {
   TRACED_FOREACH(Type*, t0, kNumberTypes) {
     Node* p0 = Parameter(t0, 0);
     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-    Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
-                                  fun, UndefinedConstant(), p0);
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
     Reduction r = Reduce(call);
 
     ASSERT_TRUE(r.Changed());
@@ -120,8 +122,9 @@ TEST_F(JSBuiltinReducerTest, MathMax0) {
   Handle<JSFunction> f(isolate()->context()->math_max_fun());
 
   Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-  Node* call = graph()->NewNode(javascript()->Call(2, NO_CALL_FUNCTION_FLAGS),
-                                fun, UndefinedConstant());
+  Node* call =
+      graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS),
+                       fun, UndefinedConstant());
   Reduction r = Reduce(call);
 
   ASSERT_TRUE(r.Changed());
@@ -135,8 +138,9 @@ TEST_F(JSBuiltinReducerTest, MathMax1) {
   TRACED_FOREACH(Type*, t0, kNumberTypes) {
     Node* p0 = Parameter(t0, 0);
     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-    Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
-                                  fun, UndefinedConstant(), p0);
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
     Reduction r = Reduce(call);
 
     ASSERT_TRUE(r.Changed());
@@ -153,9 +157,9 @@ TEST_F(JSBuiltinReducerTest, MathMax2) {
       Node* p0 = Parameter(t0, 0);
       Node* p1 = Parameter(t1, 1);
       Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-      Node* call =
-          graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
-                           UndefinedConstant(), p0, p1);
+      Node* call = graph()->NewNode(
+          javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
+          UndefinedConstant(), p0, p1);
       Reduction r = Reduce(call);
 
       if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
@@ -189,9 +193,9 @@ TEST_F(JSBuiltinReducerTest, MathImul) {
       Node* p0 = Parameter(t0, 0);
       Node* p1 = Parameter(t1, 1);
       Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-      Node* call =
-          graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
-                           UndefinedConstant(), p0, p1);
+      Node* call = graph()->NewNode(
+          javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
+          UndefinedConstant(), p0, p1);
       Reduction r = Reduce(call);
 
       if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
@@ -222,8 +226,9 @@ TEST_F(JSBuiltinReducerTest, MathFround) {
   TRACED_FOREACH(Type*, t0, kNumberTypes) {
     Node* p0 = Parameter(t0, 0);
     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-    Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
-                                  fun, UndefinedConstant(), p0);
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
     Reduction r = Reduce(call);
 
     ASSERT_TRUE(r.Changed());
index cd8932b..ed76f11 100644 (file)
@@ -67,11 +67,11 @@ Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) {
     return Reducer::NoChange();
   }
 
-  ContextAccess access = OpParameter<ContextAccess>(node);
+  const ContextAccess& access = ContextAccessOf(node->op());
 
   // Find the right parent context.
   Context* context = *m.Value().handle();
-  for (int i = access.depth(); i > 0; --i) {
+  for (size_t i = access.depth(); i > 0; --i) {
     context = context->previous();
   }
 
@@ -88,8 +88,8 @@ Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) {
     node->ReplaceInput(0, jsgraph_->Constant(context_handle));
     return Reducer::Changed(node);
   }
-  Handle<Object> value =
-      Handle<Object>(context->get(access.index()), info_->isolate());
+  Handle<Object> value = Handle<Object>(
+      context->get(static_cast<int>(access.index())), info_->isolate());
 
   // Even though the context slot is immutable, the context might have escaped
   // before the function to which it belongs has initialized the slot.
@@ -115,7 +115,7 @@ Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) {
     return Reducer::NoChange();
   }
 
-  ContextAccess access = OpParameter<ContextAccess>(node);
+  const ContextAccess& access = ContextAccessOf(node->op());
 
   // The access does not have to look up a parent, nothing to fold.
   if (access.depth() == 0) {
@@ -124,7 +124,7 @@ Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) {
 
   // Find the right parent context.
   Context* context = *m.Value().handle();
-  for (int i = access.depth(); i > 0; --i) {
+  for (size_t i = access.depth(); i > 0; --i) {
     context = context->previous();
   }
 
index 146185e..78ead5e 100644 (file)
@@ -281,9 +281,9 @@ void JSGenericLowering::LowerJSLoadProperty(Node* node) {
 
 
 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
-  LoadNamedParameters p = OpParameter<LoadNamedParameters>(node);
-  Callable callable = CodeFactory::LoadIC(isolate(), p.contextual_mode);
-  PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name));
+  const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
+  Callable callable = CodeFactory::LoadIC(isolate(), p.contextual_mode());
+  PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
 }
 
@@ -296,9 +296,9 @@ void JSGenericLowering::LowerJSStoreProperty(Node* node) {
 
 
 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
-  StoreNamedParameters params = OpParameter<StoreNamedParameters>(node);
-  Callable callable = CodeFactory::StoreIC(isolate(), params.strict_mode);
-  PatchInsertInput(node, 1, jsgraph()->HeapConstant(params.name));
+  const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
+  Callable callable = CodeFactory::StoreIC(isolate(), p.strict_mode());
+  PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
 }
 
@@ -330,10 +330,10 @@ void JSGenericLowering::LowerJSInstanceOf(Node* node) {
 
 
 void JSGenericLowering::LowerJSLoadContext(Node* node) {
-  ContextAccess access = OpParameter<ContextAccess>(node);
+  const ContextAccess& access = ContextAccessOf(node->op());
   // TODO(mstarzinger): Use simplified operators instead of machine operators
   // here so that load/store optimization can be applied afterwards.
-  for (int i = 0; i < access.depth(); ++i) {
+  for (size_t i = 0; i < access.depth(); ++i) {
     node->ReplaceInput(
         0, graph()->NewNode(
                machine()->Load(kMachAnyTagged),
@@ -341,16 +341,17 @@ void JSGenericLowering::LowerJSLoadContext(Node* node) {
                Int32Constant(Context::SlotOffset(Context::PREVIOUS_INDEX)),
                NodeProperties::GetEffectInput(node)));
   }
-  node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index())));
+  node->ReplaceInput(
+      1, Int32Constant(Context::SlotOffset(static_cast<int>(access.index()))));
   PatchOperator(node, machine()->Load(kMachAnyTagged));
 }
 
 
 void JSGenericLowering::LowerJSStoreContext(Node* node) {
-  ContextAccess access = OpParameter<ContextAccess>(node);
+  const ContextAccess& access = ContextAccessOf(node->op());
   // TODO(mstarzinger): Use simplified operators instead of machine operators
   // here so that load/store optimization can be applied afterwards.
-  for (int i = 0; i < access.depth(); ++i) {
+  for (size_t i = 0; i < access.depth(); ++i) {
     node->ReplaceInput(
         0, graph()->NewNode(
                machine()->Load(kMachAnyTagged),
@@ -359,7 +360,8 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) {
                NodeProperties::GetEffectInput(node)));
   }
   node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
-  node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index())));
+  node->ReplaceInput(
+      1, Int32Constant(Context::SlotOffset(static_cast<int>(access.index()))));
   PatchOperator(node, machine()->Store(StoreRepresentation(kMachAnyTagged,
                                                            kFullWriteBarrier)));
 }
@@ -382,11 +384,11 @@ void JSGenericLowering::LowerJSCallConstruct(Node* node) {
 
 
 void JSGenericLowering::LowerJSCallFunction(Node* node) {
-  CallParameters p = OpParameter<CallParameters>(node);
-  CallFunctionStub stub(isolate(), p.arity - 2, p.flags);
+  const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
+  CallFunctionStub stub(isolate(), static_cast<int>(p.arity() - 2), p.flags());
   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
-  CallDescriptor* desc =
-      linkage()->GetStubCallDescriptor(d, p.arity - 1, FlagsForNode(node));
+  CallDescriptor* desc = linkage()->GetStubCallDescriptor(
+      d, static_cast<int>(p.arity() - 1), FlagsForNode(node));
   Node* stub_code = CodeConstant(stub.GetCode());
   PatchInsertInput(node, 0, stub_code);
   PatchOperator(node, common()->Call(desc));
@@ -394,9 +396,8 @@ void JSGenericLowering::LowerJSCallFunction(Node* node) {
 
 
 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
-  Runtime::FunctionId function = OpParameter<Runtime::FunctionId>(node);
-  int arity = OperatorProperties::GetValueInputCount(node->op());
-  ReplaceWithRuntimeCall(node, function, arity);
+  const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
+  ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
 }
 
 }  // namespace compiler
index 400f806..b2f46fb 100644 (file)
@@ -5,13 +5,12 @@
 #ifndef V8_COMPILER_JS_GENERIC_LOWERING_H_
 #define V8_COMPILER_JS_GENERIC_LOWERING_H_
 
-#include "src/v8.h"
-
 #include "src/allocation.h"
 #include "src/code-factory.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-reducer.h"
 #include "src/compiler/js-graph.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/opcodes.h"
 
 namespace v8 {
diff --git a/src/compiler/js-operator-unittest.cc b/src/compiler/js-operator-unittest.cc
new file mode 100644 (file)
index 0000000..fda1402
--- /dev/null
@@ -0,0 +1,152 @@
+// 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-operator.h"
+#include "src/compiler/operator-properties-inl.h"
+#include "src/test/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Shared operators.
+
+namespace {
+
+struct SharedOperator {
+  const Operator* (JSOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  Operator::Properties properties;
+  int value_input_count;
+  int frame_state_input_count;
+  int effect_input_count;
+  int control_input_count;
+  int value_output_count;
+  int effect_output_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const SharedOperator& sop) {
+  return os << IrOpcode::Mnemonic(sop.opcode);
+}
+
+
+const SharedOperator kSharedOperators[] = {
+#define SHARED(Name, properties, value_input_count, frame_state_input_count, \
+               effect_input_count, control_input_count, value_output_count,  \
+               effect_output_count)                                          \
+  {                                                                          \
+    &JSOperatorBuilder::Name, IrOpcode::kJS##Name, properties,               \
+        value_input_count, frame_state_input_count, effect_input_count,      \
+        control_input_count, value_output_count, effect_output_count         \
+  }
+    SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0),
+    SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0),
+    SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseOr, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseXor, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseAnd, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftLeft, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftRight, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Add, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Subtract, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Multiply, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Divide, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Modulus, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(UnaryNot, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToBoolean, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToNumber, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToName, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToObject, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(Create, Operator::kEliminatable, 0, 0, 1, 0, 1, 1),
+    SHARED(LoadProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(HasProperty, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0),
+    SHARED(InstanceOf, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(Debugger, Operator::kNoProperties, 0, 0, 1, 1, 0, 1),
+    SHARED(CreateFunctionContext, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(CreateWithContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateBlockContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateGlobalContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1)
+#undef SHARED
+};
+
+}  // namespace
+
+
+class JSSharedOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<SharedOperator> {};
+
+
+TEST_P(JSSharedOperatorTest, InstancesAreGloballyShared) {
+  const SharedOperator& sop = GetParam();
+  JSOperatorBuilder javascript1(zone());
+  JSOperatorBuilder javascript2(zone());
+  EXPECT_EQ((javascript1.*sop.constructor)(), (javascript2.*sop.constructor)());
+}
+
+
+TEST_P(JSSharedOperatorTest, NumberOfInputsAndOutputs) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+
+  const int context_input_count = 1;
+  // TODO(jarin): Get rid of this hack.
+  const int frame_state_input_count =
+      FLAG_turbo_deoptimization ? sop.frame_state_input_count : 0;
+  EXPECT_EQ(sop.value_input_count, OperatorProperties::GetValueInputCount(op));
+  EXPECT_EQ(context_input_count, OperatorProperties::GetContextInputCount(op));
+  EXPECT_EQ(frame_state_input_count,
+            OperatorProperties::GetFrameStateInputCount(op));
+  EXPECT_EQ(sop.effect_input_count,
+            OperatorProperties::GetEffectInputCount(op));
+  EXPECT_EQ(sop.control_input_count,
+            OperatorProperties::GetControlInputCount(op));
+  EXPECT_EQ(sop.value_input_count + context_input_count +
+                frame_state_input_count + sop.effect_input_count +
+                sop.control_input_count,
+            OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(sop.value_output_count,
+            OperatorProperties::GetValueOutputCount(op));
+  EXPECT_EQ(sop.effect_output_count,
+            OperatorProperties::GetEffectOutputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+}
+
+
+TEST_P(JSSharedOperatorTest, OpcodeIsCorrect) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+  EXPECT_EQ(sop.opcode, op->opcode());
+}
+
+
+TEST_P(JSSharedOperatorTest, Properties) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+  EXPECT_EQ(sop.properties, op->properties());
+}
+
+
+INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSSharedOperatorTest,
+                        ::testing::ValuesIn(kSharedOperators));
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc
new file mode 100644 (file)
index 0000000..a10bcda
--- /dev/null
@@ -0,0 +1,251 @@
+// 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-operator.h"
+
+#include <limits>
+
+#include "src/base/lazy-instance.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+const CallFunctionParameters& CallFunctionParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSCallFunction, op->opcode());
+  return OpParameter<CallFunctionParameters>(op);
+}
+
+
+const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSCallRuntime, op->opcode());
+  return OpParameter<CallRuntimeParameters>(op);
+}
+
+
+ContextAccess::ContextAccess(size_t depth, size_t index, bool immutable)
+    : immutable_(immutable),
+      depth_(static_cast<uint16_t>(depth)),
+      index_(static_cast<uint32_t>(index)) {
+  DCHECK(depth <= std::numeric_limits<uint16_t>::max());
+  DCHECK(index <= std::numeric_limits<uint32_t>::max());
+}
+
+
+bool operator==(const ContextAccess& lhs, const ContextAccess& rhs) {
+  return lhs.depth() == rhs.depth() && lhs.index() == rhs.index() &&
+         lhs.immutable() == rhs.immutable();
+}
+
+
+bool operator!=(const ContextAccess& lhs, const ContextAccess& rhs) {
+  return !(lhs == rhs);
+}
+
+
+const ContextAccess& ContextAccessOf(const Operator* op) {
+  DCHECK(op->opcode() == IrOpcode::kJSLoadContext ||
+         op->opcode() == IrOpcode::kJSStoreContext);
+  return OpParameter<ContextAccess>(op);
+}
+
+
+const LoadNamedParameters& LoadNamedParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
+  return OpParameter<LoadNamedParameters>(op);
+}
+
+
+const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSStoreNamed, op->opcode());
+  return OpParameter<StoreNamedParameters>(op);
+}
+
+
+// Specialization for static parameters of type {ContextAccess}.
+template <>
+struct StaticParameterTraits<ContextAccess> {
+  static std::ostream& PrintTo(std::ostream& os, const ContextAccess& access) {
+    return os << access.depth() << "," << access.index()
+              << (access.immutable() ? ",imm" : "");
+  }
+  static int HashCode(const ContextAccess& access) {
+    return static_cast<int>((access.depth() << 16) | (access.index() & 0xffff));
+  }
+  static bool Equals(const ContextAccess& lhs, const ContextAccess& rhs) {
+    return lhs == rhs;
+  }
+};
+
+
+// Specialization for static parameters of type {Runtime::FunctionId}.
+template <>
+struct StaticParameterTraits<Runtime::FunctionId> {
+  static std::ostream& PrintTo(std::ostream& os, Runtime::FunctionId val) {
+    const Runtime::Function* f = Runtime::FunctionForId(val);
+    return os << (f->name ? f->name : "?Runtime?");
+  }
+  static int HashCode(Runtime::FunctionId val) { return static_cast<int>(val); }
+  static bool Equals(Runtime::FunctionId a, Runtime::FunctionId b) {
+    return a == b;
+  }
+};
+
+
+#define SHARED_OP_LIST(V)                                 \
+  V(Equal, Operator::kNoProperties, 2, 1)                 \
+  V(NotEqual, Operator::kNoProperties, 2, 1)              \
+  V(StrictEqual, Operator::kPure, 2, 1)                   \
+  V(StrictNotEqual, Operator::kPure, 2, 1)                \
+  V(LessThan, Operator::kNoProperties, 2, 1)              \
+  V(GreaterThan, Operator::kNoProperties, 2, 1)           \
+  V(LessThanOrEqual, Operator::kNoProperties, 2, 1)       \
+  V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1)    \
+  V(BitwiseOr, Operator::kNoProperties, 2, 1)             \
+  V(BitwiseXor, Operator::kNoProperties, 2, 1)            \
+  V(BitwiseAnd, Operator::kNoProperties, 2, 1)            \
+  V(ShiftLeft, Operator::kNoProperties, 2, 1)             \
+  V(ShiftRight, Operator::kNoProperties, 2, 1)            \
+  V(ShiftRightLogical, Operator::kNoProperties, 2, 1)     \
+  V(Add, Operator::kNoProperties, 2, 1)                   \
+  V(Subtract, Operator::kNoProperties, 2, 1)              \
+  V(Multiply, Operator::kNoProperties, 2, 1)              \
+  V(Divide, Operator::kNoProperties, 2, 1)                \
+  V(Modulus, Operator::kNoProperties, 2, 1)               \
+  V(UnaryNot, Operator::kNoProperties, 1, 1)              \
+  V(ToBoolean, Operator::kNoProperties, 1, 1)             \
+  V(ToNumber, Operator::kNoProperties, 1, 1)              \
+  V(ToString, Operator::kNoProperties, 1, 1)              \
+  V(ToName, Operator::kNoProperties, 1, 1)                \
+  V(ToObject, Operator::kNoProperties, 1, 1)              \
+  V(Yield, Operator::kNoProperties, 1, 1)                 \
+  V(Create, Operator::kEliminatable, 0, 1)                \
+  V(LoadProperty, Operator::kNoProperties, 2, 1)          \
+  V(HasProperty, Operator::kNoProperties, 2, 1)           \
+  V(TypeOf, Operator::kPure, 1, 1)                        \
+  V(InstanceOf, Operator::kNoProperties, 2, 1)            \
+  V(Debugger, Operator::kNoProperties, 0, 0)              \
+  V(CreateFunctionContext, Operator::kNoProperties, 1, 1) \
+  V(CreateWithContext, Operator::kNoProperties, 2, 1)     \
+  V(CreateBlockContext, Operator::kNoProperties, 2, 1)    \
+  V(CreateModuleContext, Operator::kNoProperties, 2, 1)   \
+  V(CreateGlobalContext, Operator::kNoProperties, 2, 1)
+
+
+struct JSOperatorBuilderImpl FINAL {
+#define SHARED(Name, properties, value_input_count, value_output_count)      \
+  struct Name##Operator FINAL : public SimpleOperator {                      \
+    Name##Operator()                                                         \
+        : SimpleOperator(IrOpcode::kJS##Name, properties, value_input_count, \
+                         value_output_count, "JS" #Name) {}                  \
+  };                                                                         \
+  Name##Operator k##Name##Operator;
+  SHARED_OP_LIST(SHARED)
+#undef SHARED
+};
+
+
+static base::LazyInstance<JSOperatorBuilderImpl>::type kImpl =
+    LAZY_INSTANCE_INITIALIZER;
+
+
+JSOperatorBuilder::JSOperatorBuilder(Zone* zone)
+    : impl_(kImpl.Get()), zone_(zone) {}
+
+
+#define SHARED(Name, properties, value_input_count, value_output_count) \
+  const Operator* JSOperatorBuilder::Name() { return &impl_.k##Name##Operator; }
+SHARED_OP_LIST(SHARED)
+#undef SHARED
+
+
+const Operator* JSOperatorBuilder::CallFunction(size_t arity,
+                                                CallFunctionFlags flags) {
+  CallFunctionParameters parameters(arity, flags);
+  return new (zone()) Operator1<CallFunctionParameters>(
+      IrOpcode::kJSCallFunction, Operator::kNoProperties,
+      static_cast<int>(parameters.arity()), 1, "JSCallFunction", parameters);
+}
+
+
+const Operator* JSOperatorBuilder::CallRuntime(Runtime::FunctionId id,
+                                               size_t arity) {
+  CallRuntimeParameters parameters(id, arity);
+  const Runtime::Function* f = Runtime::FunctionForId(parameters.id());
+  int arguments = static_cast<int>(parameters.arity());
+  DCHECK(f->nargs == -1 || f->nargs == arguments);
+  return new (zone()) Operator1<CallRuntimeParameters>(
+      IrOpcode::kJSCallRuntime, Operator::kNoProperties, arguments,
+      f->result_size, "JSCallRuntime", parameters);
+}
+
+
+const Operator* JSOperatorBuilder::CallConstruct(int arguments) {
+  return new (zone())
+      Operator1<int>(IrOpcode::kJSCallConstruct, Operator::kNoProperties,
+                     arguments, 1, "JSCallConstruct", arguments);
+}
+
+
+const Operator* JSOperatorBuilder::LoadNamed(const Unique<Name>& name,
+                                             ContextualMode contextual_mode) {
+  LoadNamedParameters parameters(name, contextual_mode);
+  return new (zone()) Operator1<LoadNamedParameters>(
+      IrOpcode::kJSLoadNamed, Operator::kNoProperties, 1, 1, "JSLoadNamed",
+      parameters);
+}
+
+
+const Operator* JSOperatorBuilder::StoreProperty(StrictMode strict_mode) {
+  return new (zone())
+      Operator1<StrictMode>(IrOpcode::kJSStoreProperty, Operator::kNoProperties,
+                            3, 0, "JSStoreProperty", strict_mode);
+}
+
+
+const Operator* JSOperatorBuilder::StoreNamed(StrictMode strict_mode,
+                                              const Unique<Name>& name) {
+  StoreNamedParameters parameters(strict_mode, name);
+  return new (zone()) Operator1<StoreNamedParameters>(
+      IrOpcode::kJSStoreNamed, Operator::kNoProperties, 2, 0, "JSStoreNamed",
+      parameters);
+}
+
+
+const Operator* JSOperatorBuilder::DeleteProperty(StrictMode strict_mode) {
+  return new (zone()) Operator1<StrictMode>(IrOpcode::kJSDeleteProperty,
+                                            Operator::kNoProperties, 2, 1,
+                                            "JSDeleteProperty", strict_mode);
+}
+
+
+const Operator* JSOperatorBuilder::LoadContext(size_t depth, size_t index,
+                                               bool immutable) {
+  ContextAccess access(depth, index, immutable);
+  return new (zone()) Operator1<ContextAccess>(
+      IrOpcode::kJSLoadContext, Operator::kEliminatable | Operator::kNoWrite, 1,
+      1, "JSLoadContext", access);
+}
+
+
+const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
+  ContextAccess access(depth, index, false);
+  return new (zone()) Operator1<ContextAccess>(IrOpcode::kJSStoreContext,
+                                               Operator::kNoProperties, 2, 0,
+                                               "JSStoreContext", access);
+}
+
+
+const Operator* JSOperatorBuilder::CreateCatchContext(
+    const Unique<String>& name) {
+  return new (zone()) Operator1<Unique<String> >(
+      IrOpcode::kJSCreateCatchContext, Operator::kNoProperties, 1, 1,
+      "JSCreateCatchContext", name);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index 5cf6d53..909d7f2 100644 (file)
@@ -5,28 +5,63 @@
 #ifndef V8_COMPILER_JS_OPERATOR_H_
 #define V8_COMPILER_JS_OPERATOR_H_
 
-#include "src/compiler/linkage.h"
-#include "src/compiler/opcodes.h"
-#include "src/compiler/operator.h"
+#include "src/runtime/runtime.h"
 #include "src/unique.h"
-#include "src/zone.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
+class Operator;
+struct JSOperatorBuilderImpl;
+
+
+// Defines the arity and the call flags for a JavaScript function call. This is
+// used as a parameter by JSCallFunction operators.
+class CallFunctionParameters FINAL {
+ public:
+  CallFunctionParameters(size_t arity, CallFunctionFlags flags)
+      : arity_(arity), flags_(flags) {}
+
+  size_t arity() const { return arity_; }
+  CallFunctionFlags flags() const { return flags_; }
+
+ private:
+  const size_t arity_;
+  const CallFunctionFlags flags_;
+};
+
+const CallFunctionParameters& CallFunctionParametersOf(const Operator* op);
+
+
+// Defines the arity and the ID for a runtime function call. This is used as a
+// parameter by JSCallRuntime operators.
+class CallRuntimeParameters FINAL {
+ public:
+  CallRuntimeParameters(Runtime::FunctionId id, size_t arity)
+      : id_(id), arity_(arity) {}
+
+  Runtime::FunctionId id() const { return id_; }
+  size_t arity() const { return arity_; }
+
+ private:
+  const Runtime::FunctionId id_;
+  const size_t arity_;
+};
+
+const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op);
+
+
 // Defines the location of a context slot relative to a specific scope. This is
 // used as a parameter by JSLoadContext and JSStoreContext operators and allows
 // accessing a context-allocated variable without keeping track of the scope.
-class ContextAccess {
+class ContextAccess FINAL {
  public:
-  ContextAccess(int depth, int index, bool immutable)
-      : immutable_(immutable), depth_(depth), index_(index) {
-    DCHECK(0 <= depth && depth <= kMaxUInt16);
-    DCHECK(0 <= index && static_cast<uint32_t>(index) <= kMaxUInt32);
-  }
-  int depth() const { return depth_; }
-  int index() const { return index_; }
+  ContextAccess(size_t depth, size_t index, bool immutable);
+
+  size_t depth() const { return depth_; }
+  size_t index() const { return index_; }
   bool immutable() const { return immutable_; }
 
  private:
@@ -37,194 +72,121 @@ class ContextAccess {
   const uint32_t index_;
 };
 
+bool operator==(const ContextAccess& lhs, const ContextAccess& rhs);
+bool operator!=(const ContextAccess& lhs, const ContextAccess& rhs);
+
+const ContextAccess& ContextAccessOf(const Operator* op);
+
+
 // Defines the property being loaded from an object by a named load. This is
 // used as a parameter by JSLoadNamed operators.
-struct LoadNamedParameters {
-  Unique<Name> name;
-  ContextualMode contextual_mode;
-};
+class LoadNamedParameters FINAL {
+ public:
+  LoadNamedParameters(const Unique<Name>& name, ContextualMode contextual_mode)
+      : name_(name), contextual_mode_(contextual_mode) {}
 
-// Defines the arity and the call flags for a JavaScript function call. This is
-// used as a parameter by JSCall operators.
-struct CallParameters {
-  int arity;
-  CallFunctionFlags flags;
+  const Unique<Name>& name() const { return name_; }
+  ContextualMode contextual_mode() const { return contextual_mode_; }
+
+ private:
+  const Unique<Name> name_;
+  const ContextualMode contextual_mode_;
 };
 
+const LoadNamedParameters& LoadNamedParametersOf(const Operator* op);
+
+
 // Defines the property being stored to an object by a named store. This is
 // used as a parameter by JSStoreNamed operators.
-struct StoreNamedParameters {
-  StrictMode strict_mode;
-  Unique<Name> name;
+class StoreNamedParameters FINAL {
+ public:
+  StoreNamedParameters(StrictMode strict_mode, const Unique<Name>& name)
+      : strict_mode_(strict_mode), name_(name) {}
+
+  StrictMode strict_mode() const { return strict_mode_; }
+  const Unique<Name>& name() const { return name_; }
+
+ private:
+  const StrictMode strict_mode_;
+  const Unique<Name> name_;
 };
 
+const StoreNamedParameters& StoreNamedParametersOf(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.
-class JSOperatorBuilder {
+class JSOperatorBuilder FINAL {
  public:
-  explicit JSOperatorBuilder(Zone* zone) : zone_(zone) {}
-
-#define SIMPLE(name, properties, inputs, outputs) \
-  return new (zone_)                              \
-      SimpleOperator(IrOpcode::k##name, properties, inputs, outputs, #name);
-
-#define NOPROPS(name, inputs, outputs) \
-  SIMPLE(name, Operator::kNoProperties, inputs, outputs)
-
-#define OP1(name, ptype, pname, properties, inputs, outputs)                 \
-  return new (zone_) Operator1<ptype>(IrOpcode::k##name, properties, inputs, \
-                                      outputs, #name, pname)
-
-#define BINOP(name) NOPROPS(name, 2, 1)
-#define UNOP(name) NOPROPS(name, 1, 1)
-
-#define PURE_BINOP(name) SIMPLE(name, Operator::kPure, 2, 1)
-
-  const Operator* Equal() { BINOP(JSEqual); }
-  const Operator* NotEqual() { BINOP(JSNotEqual); }
-  const Operator* StrictEqual() { PURE_BINOP(JSStrictEqual); }
-  const Operator* StrictNotEqual() { PURE_BINOP(JSStrictNotEqual); }
-  const Operator* LessThan() { BINOP(JSLessThan); }
-  const Operator* GreaterThan() { BINOP(JSGreaterThan); }
-  const Operator* LessThanOrEqual() { BINOP(JSLessThanOrEqual); }
-  const Operator* GreaterThanOrEqual() { BINOP(JSGreaterThanOrEqual); }
-  const Operator* BitwiseOr() { BINOP(JSBitwiseOr); }
-  const Operator* BitwiseXor() { BINOP(JSBitwiseXor); }
-  const Operator* BitwiseAnd() { BINOP(JSBitwiseAnd); }
-  const Operator* ShiftLeft() { BINOP(JSShiftLeft); }
-  const Operator* ShiftRight() { BINOP(JSShiftRight); }
-  const Operator* ShiftRightLogical() { BINOP(JSShiftRightLogical); }
-  const Operator* Add() { BINOP(JSAdd); }
-  const Operator* Subtract() { BINOP(JSSubtract); }
-  const Operator* Multiply() { BINOP(JSMultiply); }
-  const Operator* Divide() { BINOP(JSDivide); }
-  const Operator* Modulus() { BINOP(JSModulus); }
-
-  const Operator* UnaryNot() { UNOP(JSUnaryNot); }
-  const Operator* ToBoolean() { UNOP(JSToBoolean); }
-  const Operator* ToNumber() { UNOP(JSToNumber); }
-  const Operator* ToString() { UNOP(JSToString); }
-  const Operator* ToName() { UNOP(JSToName); }
-  const Operator* ToObject() { UNOP(JSToObject); }
-  const Operator* Yield() { UNOP(JSYield); }
-
-  const Operator* Create() { SIMPLE(JSCreate, Operator::kEliminatable, 0, 1); }
-
-  const Operator* Call(int arguments, CallFunctionFlags flags) {
-    CallParameters parameters = {arguments, flags};
-    OP1(JSCallFunction, CallParameters, parameters, Operator::kNoProperties,
-        arguments, 1);
-  }
-
-  const Operator* CallNew(int arguments) {
-    return new (zone_)
-        Operator1<int>(IrOpcode::kJSCallConstruct, Operator::kNoProperties,
-                       arguments, 1, "JSCallConstruct", arguments);
-  }
-
-  const Operator* LoadProperty() { BINOP(JSLoadProperty); }
-  const Operator* LoadNamed(Unique<Name> name,
-                            ContextualMode contextual_mode = NOT_CONTEXTUAL) {
-    LoadNamedParameters parameters = {name, contextual_mode};
-    OP1(JSLoadNamed, LoadNamedParameters, parameters, Operator::kNoProperties,
-        1, 1);
-  }
-
-  const Operator* StoreProperty(StrictMode strict_mode) {
-    OP1(JSStoreProperty, StrictMode, strict_mode, Operator::kNoProperties, 3,
-        0);
-  }
-
-  const Operator* StoreNamed(StrictMode strict_mode, Unique<Name> name) {
-    StoreNamedParameters parameters = {strict_mode, name};
-    OP1(JSStoreNamed, StoreNamedParameters, parameters, Operator::kNoProperties,
-        2, 0);
-  }
-
-  const Operator* DeleteProperty(StrictMode strict_mode) {
-    OP1(JSDeleteProperty, StrictMode, strict_mode, Operator::kNoProperties, 2,
-        1);
-  }
-
-  const Operator* HasProperty() { NOPROPS(JSHasProperty, 2, 1); }
-
-  const Operator* LoadContext(uint16_t depth, uint32_t index, bool immutable) {
-    ContextAccess access(depth, index, immutable);
-    OP1(JSLoadContext, ContextAccess, access,
-        Operator::kEliminatable | Operator::kNoWrite, 1, 1);
-  }
-  const Operator* StoreContext(uint16_t depth, uint32_t index) {
-    ContextAccess access(depth, index, false);
-    OP1(JSStoreContext, ContextAccess, access, Operator::kNoProperties, 2, 0);
-  }
-
-  const Operator* TypeOf() { SIMPLE(JSTypeOf, Operator::kPure, 1, 1); }
-  const Operator* InstanceOf() { NOPROPS(JSInstanceOf, 2, 1); }
-  const Operator* Debugger() { NOPROPS(JSDebugger, 0, 0); }
+  explicit JSOperatorBuilder(Zone* zone);
+
+  const Operator* Equal();
+  const Operator* NotEqual();
+  const Operator* StrictEqual();
+  const Operator* StrictNotEqual();
+  const Operator* LessThan();
+  const Operator* GreaterThan();
+  const Operator* LessThanOrEqual();
+  const Operator* GreaterThanOrEqual();
+  const Operator* BitwiseOr();
+  const Operator* BitwiseXor();
+  const Operator* BitwiseAnd();
+  const Operator* ShiftLeft();
+  const Operator* ShiftRight();
+  const Operator* ShiftRightLogical();
+  const Operator* Add();
+  const Operator* Subtract();
+  const Operator* Multiply();
+  const Operator* Divide();
+  const Operator* Modulus();
+
+  const Operator* UnaryNot();
+  const Operator* ToBoolean();
+  const Operator* ToNumber();
+  const Operator* ToString();
+  const Operator* ToName();
+  const Operator* ToObject();
+  const Operator* Yield();
+
+  const Operator* Create();
+
+  const Operator* CallFunction(size_t arity, CallFunctionFlags flags);
+  const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
+
+  const Operator* CallConstruct(int arguments);
+
+  const Operator* LoadProperty();
+  const Operator* LoadNamed(const Unique<Name>& name,
+                            ContextualMode contextual_mode = NOT_CONTEXTUAL);
+
+  const Operator* StoreProperty(StrictMode strict_mode);
+  const Operator* StoreNamed(StrictMode strict_mode, const Unique<Name>& name);
+
+  const Operator* DeleteProperty(StrictMode strict_mode);
+
+  const Operator* HasProperty();
+
+  const Operator* LoadContext(size_t depth, size_t index, bool immutable);
+  const Operator* StoreContext(size_t depth, size_t index);
+
+  const Operator* TypeOf();
+  const Operator* InstanceOf();
+  const Operator* Debugger();
 
   // TODO(titzer): nail down the static parts of each of these context flavors.
-  const Operator* CreateFunctionContext() {
-    NOPROPS(JSCreateFunctionContext, 1, 1);
-  }
-  const Operator* CreateCatchContext(Unique<String> name) {
-    OP1(JSCreateCatchContext, Unique<String>, name, Operator::kNoProperties, 1,
-        1);
-  }
-  const Operator* CreateWithContext() { NOPROPS(JSCreateWithContext, 2, 1); }
-  const Operator* CreateBlockContext() { NOPROPS(JSCreateBlockContext, 2, 1); }
-  const Operator* CreateModuleContext() {
-    NOPROPS(JSCreateModuleContext, 2, 1);
-  }
-  const Operator* CreateGlobalContext() {
-    NOPROPS(JSCreateGlobalContext, 2, 1);
-  }
-
-  const Operator* Runtime(Runtime::FunctionId function, int arguments) {
-    const Runtime::Function* f = Runtime::FunctionForId(function);
-    DCHECK(f->nargs == -1 || f->nargs == arguments);
-    OP1(JSCallRuntime, Runtime::FunctionId, function, Operator::kNoProperties,
-        arguments, f->result_size);
-  }
-
-#undef SIMPLE
-#undef NOPROPS
-#undef OP1
-#undef BINOP
-#undef UNOP
+  const Operator* CreateFunctionContext();
+  const Operator* CreateCatchContext(const Unique<String>& name);
+  const Operator* CreateWithContext();
+  const Operator* CreateBlockContext();
+  const Operator* CreateModuleContext();
+  const Operator* CreateGlobalContext();
 
  private:
-  Zone* zone_;
-};
-
-// Specialization for static parameters of type {ContextAccess}.
-template <>
-struct StaticParameterTraits<ContextAccess> {
-  static std::ostream& PrintTo(std::ostream& os, ContextAccess val) {  // NOLINT
-    return os << val.depth() << "," << val.index()
-              << (val.immutable() ? ",imm" : "");
-  }
-  static int HashCode(ContextAccess val) {
-    return (val.depth() << 16) | (val.index() & 0xffff);
-  }
-  static bool Equals(ContextAccess a, ContextAccess b) {
-    return a.immutable() == b.immutable() && a.depth() == b.depth() &&
-           a.index() == b.index();
-  }
-};
+  Zone* zone() const { return zone_; }
 
-// Specialization for static parameters of type {Runtime::FunctionId}.
-template <>
-struct StaticParameterTraits<Runtime::FunctionId> {
-  static std::ostream& PrintTo(std::ostream& os,
-                               Runtime::FunctionId val) {  // NOLINT
-    const Runtime::Function* f = Runtime::FunctionForId(val);
-    return os << (f->name ? f->name : "?Runtime?");
-  }
-  static int HashCode(Runtime::FunctionId val) { return static_cast<int>(val); }
-  static bool Equals(Runtime::FunctionId a, Runtime::FunctionId b) {
-    return a == b;
-  }
+  const JSOperatorBuilderImpl& impl_;
+  Zone* const zone_;
 };
 
 }  // namespace compiler
index fa31d05..d6b3ff2 100644 (file)
@@ -5,6 +5,7 @@
 #include "src/compiler/machine-operator-reducer.h"
 
 #include "src/base/bits.h"
+#include "src/codegen.h"
 #include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/js-graph.h"
index cb598aa..51d43d4 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "src/compiler/common-operator.h"
 #include "src/compiler/js-operator.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator-properties.h"
 
@@ -40,8 +41,8 @@ inline bool OperatorProperties::HasFrameStateInput(const Operator* op) {
     case IrOpcode::kFrameState:
       return true;
     case IrOpcode::kJSCallRuntime: {
-      Runtime::FunctionId function = OpParameter<Runtime::FunctionId>(op);
-      return Linkage::NeedsFrameState(function);
+      const CallRuntimeParameters& p = CallRuntimeParametersOf(op);
+      return Linkage::NeedsFrameState(p.id());
     }
 
     // Strict equality cannot lazily deoptimize.
index b6349c9..8be542e 100644 (file)
@@ -557,7 +557,7 @@ Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
   // bound.
   // TODO(rossberg): Could use scope info to fix upper bounds for constant
   // bindings if we know that this code is never shared.
-  for (int i = access.depth(); i > 0; --i) {
+  for (size_t i = access.depth(); i > 0; --i) {
     if (context_type->IsContext()) {
       context_type = context_type->AsContext()->Outer();
       if (context_type->IsConstant()) {
@@ -571,7 +571,8 @@ Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
     return Bounds::Unbounded(zone());
   } else {
     Handle<Object> value =
-        handle(context.ToHandleChecked()->get(access.index()), isolate());
+        handle(context.ToHandleChecked()->get(static_cast<int>(access.index())),
+               isolate());
     Type* lower = TypeConstant(value);
     return Bounds(lower, Type::Any(zone()));
   }
index da8511b..eafb19f 100644 (file)
@@ -6,6 +6,7 @@
 #define V8_RUNTIME_H_
 
 #include "src/allocation.h"
+#include "src/objects.h"
 #include "src/zone.h"
 
 namespace v8 {
index 47c660a..46d6e43 100644 (file)
@@ -95,8 +95,8 @@ TEST(ReduceJSLoadContext) {
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 
@@ -175,8 +175,8 @@ TEST(ReduceJSStoreContext) {
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 }
index 9a41bc5..d3b4920 100644 (file)
@@ -5,6 +5,7 @@
 #include "test/cctest/cctest.h"
 
 #include "src/base/utils/random-number-generator.h"
+#include "src/codegen.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator-reducer.h"
index 0d86c7d..a7ececd 100644 (file)
         '../../src/compiler/js-graph.h',
         '../../src/compiler/js-inlining.cc',
         '../../src/compiler/js-inlining.h',
+        '../../src/compiler/js-operator.cc',
         '../../src/compiler/js-operator.h',
         '../../src/compiler/js-typed-lowering.cc',
         '../../src/compiler/js-typed-lowering.h',