[turbofan] Remove the TryLowerDirectJSCall hack from generic lowering.
authorbmeurer <bmeurer@chromium.org>
Mon, 15 Jun 2015 14:06:11 +0000 (07:06 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 15 Jun 2015 14:06:18 +0000 (14:06 +0000)
The TryLowerDirectJSCall method tried to lower to a direct JavaScript
function call depending on the type of the receiver, but only if the
target is a cosntant JSFunction. Since this depends on types and is not
required for correctness, it shouldn't be part of generic lowering
anyway. So this functionality was moved to typed lowering instead, and
we use proper types for the target instead.

R=mstarzinger@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#29028}

src/compiler/js-generic-lowering.cc
src/compiler/js-generic-lowering.h
src/compiler/js-typed-lowering.cc
src/compiler/js-typed-lowering.h
src/compiler/typer.cc
src/types.h

index 322654c..51b4f10 100644 (file)
@@ -514,44 +514,7 @@ void JSGenericLowering::LowerJSCallConstruct(Node* node) {
 }
 
 
-bool JSGenericLowering::TryLowerDirectJSCall(Node* node) {
-  // Lower to a direct call to a constant JSFunction if legal.
-  const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
-  int arg_count = static_cast<int>(p.arity() - 2);
-
-  // Check the function is a constant and is really a JSFunction.
-  HeapObjectMatcher<Object> function_const(node->InputAt(0));
-  if (!function_const.HasValue()) return false;  // not a constant.
-  Handle<Object> func = function_const.Value().handle();
-  if (!func->IsJSFunction()) return false;  // not a function.
-  Handle<JSFunction> function = Handle<JSFunction>::cast(func);
-  if (arg_count != function->shared()->internal_formal_parameter_count()) {
-    return false;
-  }
-
-  // Check the receiver doesn't need to be wrapped.
-  Node* receiver = node->InputAt(1);
-  if (!NodeProperties::IsTyped(receiver)) return false;
-  Type* ok_receiver = Type::Union(Type::Undefined(), Type::Receiver(), zone());
-  if (!NodeProperties::GetBounds(receiver).upper->Is(ok_receiver)) return false;
-
-  // Update to the function context.
-  NodeProperties::ReplaceContextInput(
-      node, jsgraph()->HeapConstant(Handle<Context>(function->context())));
-  CallDescriptor::Flags flags = FlagsForNode(node);
-  if (is_strict(p.language_mode())) flags |= CallDescriptor::kSupportsTailCalls;
-  CallDescriptor* desc =
-      Linkage::GetJSCallDescriptor(zone(), false, 1 + arg_count, flags);
-  node->set_op(common()->Call(desc));
-  return true;
-}
-
-
 void JSGenericLowering::LowerJSCallFunction(Node* node) {
-  // Fast case: call function directly.
-  if (TryLowerDirectJSCall(node)) return;
-
-  // General case: CallFunctionStub.
   const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
   int arg_count = static_cast<int>(p.arity() - 2);
   CallFunctionStub stub(isolate(), arg_count, p.flags());
index 89467db..9811ba8 100644 (file)
@@ -41,9 +41,6 @@ class JSGenericLowering final : public Reducer {
   void ReplaceWithBuiltinCall(Node* node, Builtins::JavaScript id, int args);
   void ReplaceWithRuntimeCall(Node* node, Runtime::FunctionId f, int args = -1);
 
-  // Helper for optimization of JSCallFunction.
-  bool TryLowerDirectJSCall(Node* node);
-
   Zone* zone() const;
   Isolate* isolate() const;
   JSGraph* jsgraph() const { return jsgraph_; }
index f3b8012..94fae66 100644 (file)
@@ -1263,6 +1263,39 @@ Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) {
 }
 
 
+Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
+  DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
+  CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
+  int const arity = static_cast<int>(p.arity() - 2);
+  Node* const function = NodeProperties::GetValueInput(node, 0);
+  Type* const function_type = NodeProperties::GetBounds(function).upper;
+  Node* const receiver = NodeProperties::GetValueInput(node, 1);
+  Type* const receiver_type = NodeProperties::GetBounds(receiver).upper;
+  Node* const effect = NodeProperties::GetEffectInput(node);
+  Node* const control = NodeProperties::GetControlInput(node);
+
+  // Check that {function} is actually a JSFunction with the correct arity.
+  if (function_type->IsFunction() &&
+      function_type->AsFunction()->Arity() == arity) {
+    // Check that the {receiver} doesn't need to be wrapped.
+    if (receiver_type->Is(Type::ReceiverOrUndefined())) {
+      Node* const context = graph()->NewNode(
+          simplified()->LoadField(AccessBuilder::ForJSFunctionContext()),
+          function, effect, control);
+      NodeProperties::ReplaceContextInput(node, context);
+      CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
+      if (is_strict(p.language_mode())) {
+        flags |= CallDescriptor::kSupportsTailCalls;
+      }
+      node->set_op(common()->Call(Linkage::GetJSCallDescriptor(
+          graph()->zone(), false, 1 + arity, flags)));
+      return Changed(node);
+    }
+  }
+  return NoChange();
+}
+
+
 Reduction JSTypedLowering::ReduceJSForInDone(Node* node) {
   DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode());
   node->set_op(machine()->Word32Equal());
@@ -1631,6 +1664,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
       return ReduceJSCreateWithContext(node);
     case IrOpcode::kJSCreateBlockContext:
       return ReduceJSCreateBlockContext(node);
+    case IrOpcode::kJSCallFunction:
+      return ReduceJSCallFunction(node);
     case IrOpcode::kJSForInDone:
       return ReduceJSForInDone(node);
     case IrOpcode::kJSForInNext:
index 260c900..63c1da9 100644 (file)
@@ -61,6 +61,7 @@ class JSTypedLowering final : public AdvancedReducer {
   Reduction ReduceJSCreateLiteralObject(Node* node);
   Reduction ReduceJSCreateWithContext(Node* node);
   Reduction ReduceJSCreateBlockContext(Node* node);
+  Reduction ReduceJSCallFunction(Node* node);
   Reduction ReduceJSForInDone(Node* node);
   Reduction ReduceJSForInNext(Node* node);
   Reduction ReduceJSForInPrepare(Node* node);
index 0f6c4d1..aeacad5 100644 (file)
@@ -26,6 +26,10 @@ namespace compiler {
   V(Float64)
 
 enum LazyCachedType {
+  kAnyFunc0,
+  kAnyFunc1,
+  kAnyFunc2,
+  kAnyFunc3,
   kNumberFunc0,
   kNumberFunc1,
   kNumberFunc2,
@@ -78,6 +82,15 @@ class LazyTypeCache final : public ZoneObject {
         return CreateNative(Type::Number(), Type::UntaggedFloat64());
       case kUint8Clamped:
         return Get(kUint8);
+      case kAnyFunc0:
+        return Type::Function(Type::Any(), zone());
+      case kAnyFunc1:
+        return Type::Function(Type::Any(), Type::Any(), zone());
+      case kAnyFunc2:
+        return Type::Function(Type::Any(), Type::Any(), Type::Any(), zone());
+      case kAnyFunc3:
+        return Type::Function(Type::Any(), Type::Any(), Type::Any(),
+                              Type::Any(), zone());
       case kNumberFunc0:
         return Type::Function(Type::Number(), zone());
       case kNumberFunc1:
@@ -2393,6 +2406,23 @@ Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
         return typer_->cache_->Get(kFloat64ArrayFunc);
       }
     }
+    int const arity =
+        JSFunction::cast(*value)->shared()->internal_formal_parameter_count();
+    switch (arity) {
+      case 0:
+        return typer_->cache_->Get(kAnyFunc0);
+      case 1:
+        return typer_->cache_->Get(kAnyFunc1);
+      case 2:
+        return typer_->cache_->Get(kAnyFunc2);
+      case 3:
+        return typer_->cache_->Get(kAnyFunc3);
+      default: {
+        Type** const params = zone()->NewArray<Type*>(arity);
+        std::fill(&params[0], &params[arity], Type::Any(zone()));
+        return Type::Function(Type::Any(zone()), arity, params, zone());
+      }
+    }
   } else if (value->IsJSTypedArray()) {
     switch (JSTypedArray::cast(*value)->type()) {
 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
index 8f80624..228b6d0 100644 (file)
@@ -233,6 +233,7 @@ namespace internal {
   V(Detectable,          kDetectableReceiver | kNumber | kName) \
   V(Object,              kDetectableObject | kUndetectable) \
   V(Receiver,            kObject | kProxy) \
+  V(ReceiverOrUndefined, kReceiver | kUndefined) \
   V(StringOrReceiver,    kString | kReceiver) \
   V(Unique,              kBoolean | kUniqueName | kNull | kUndefined | \
                          kReceiver) \
@@ -410,6 +411,14 @@ class TypeImpl : public Config::Base {
     function->InitParameter(2, param2);
     return function;
   }
+  static TypeHandle Function(TypeHandle result, int arity, TypeHandle* params,
+                             Region* region) {
+    FunctionHandle function = Function(result, Any(region), arity, region);
+    for (int i = 0; i < arity; ++i) {
+      function->InitParameter(i, params[i]);
+    }
+    return function;
+  }
 
   static TypeHandle Union(TypeHandle type1, TypeHandle type2, Region* reg);
   static TypeHandle Intersect(TypeHandle type1, TypeHandle type2, Region* reg);