Add inlining for intrinsics.
authorsigurds@chromium.org <sigurds@chromium.org>
Mon, 20 Oct 2014 07:56:50 +0000 (07:56 +0000)
committersigurds@chromium.org <sigurds@chromium.org>
Mon, 20 Oct 2014 07:56:50 +0000 (07:56 +0000)
This issue is for discussion on how to proceed.

I think the implementation of ValueOf shows that directly creating the IR does not scale.

BUG=
R=mstarzinger@chromium.org

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

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

19 files changed:
BUILD.gn
src/compiler/access-builder.cc
src/compiler/access-builder.h
src/compiler/graph.h
src/compiler/js-inlining.cc
src/compiler/js-inlining.h
src/compiler/js-intrinsic-builder.cc [new file with mode: 0644]
src/compiler/js-intrinsic-builder.h [new file with mode: 0644]
src/compiler/linkage.cc
src/compiler/opcodes.h
src/compiler/simplified-lowering.cc
src/compiler/simplified-operator.cc
src/compiler/simplified-operator.h
src/compiler/typer.cc
src/compiler/verifier.cc
src/flag-definitions.h
test/cctest/compiler/test-run-inlining.cc
test/cctest/compiler/test-run-intrinsics.cc
tools/gyp/v8.gyp

index 08dd231..56fded6 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -524,6 +524,8 @@ source_set("v8_base") {
     "src/compiler/js-graph.h",
     "src/compiler/js-inlining.cc",
     "src/compiler/js-inlining.h",
+    "src/compiler/js-intrinsic-builder.cc",
+    "src/compiler/js-intrinsic-builder.h",
     "src/compiler/js-operator.cc",
     "src/compiler/js-operator.h",
     "src/compiler/js-typed-lowering.cc",
index 959c60a..051b47c 100644 (file)
@@ -52,6 +52,20 @@ FieldAccess AccessBuilder::ForExternalArrayPointer() {
 
 
 // static
+FieldAccess AccessBuilder::ForMapInstanceType() {
+  return {kTaggedBase, Map::kInstanceTypeOffset, Handle<Name>(),
+          Type::UntaggedInt8(), kMachUint8};
+}
+
+
+// static
+FieldAccess AccessBuilder::ForValue() {
+  return {kTaggedBase, JSValue::kValueOffset, Handle<Name>(), Type::Any(),
+          kMachAnyTagged};
+}
+
+
+// static
 ElementAccess AccessBuilder::ForFixedArrayElement() {
   return {kNoBoundsCheck, kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
           kMachAnyTagged};
index 72dd023..73c81ef 100644 (file)
@@ -34,6 +34,12 @@ class AccessBuilder FINAL : public AllStatic {
   // Provides access to ExternalArray::external_pointer() field.
   static FieldAccess ForExternalArrayPointer();
 
+  // Provides access to Map::instance_type() field.
+  static FieldAccess ForMapInstanceType();
+
+  // Provides access to JSValue::value() field.
+  static FieldAccess ForValue();
+
   // Provides access to FixedArray elements.
   static ElementAccess ForFixedArrayElement();
 
index 8f24cf5..9b0d234 100644 (file)
@@ -55,6 +55,11 @@ class Graph : public GenericGraph<Node> {
     Node* nodes[] = {n1, n2, n3, n4, n5, n6};
     return NewNode(op, arraysize(nodes), nodes);
   }
+  Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
+                Node* n5, Node* n6, Node* n7) {
+    Node* nodes[] = {n1, n2, n3, n4, n5, n6, n7};
+    return NewNode(op, arraysize(nodes), nodes);
+  }
 
   template <class Visitor>
   void VisitNodeUsesFrom(Node* node, Visitor* visitor);
index 8762a97..f834602 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/js-inlining.h"
+#include "src/compiler/js-intrinsic-builder.h"
 #include "src/compiler/js-operator.h"
 #include "src/compiler/node-aux-data-inl.h"
 #include "src/compiler/node-matchers.h"
@@ -32,7 +33,12 @@ class InlinerVisitor : public NullNodeVisitor {
   GenericGraphVisit::Control Post(Node* node) {
     switch (node->opcode()) {
       case IrOpcode::kJSCallFunction:
-        inliner_->TryInlineCall(node);
+        inliner_->TryInlineJSCall(node);
+        break;
+      case IrOpcode::kJSCallRuntime:
+        if (FLAG_turbo_inlining_intrinsics) {
+          inliner_->TryInlineRuntimeCall(node);
+        }
         break;
       default:
         break;
@@ -285,22 +291,9 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
     }
   }
 
-  // Iterate over all uses of the call node.
-  iter = call->uses().begin();
-  while (iter != call->uses().end()) {
-    if (NodeProperties::IsEffectEdge(iter.edge())) {
-      iter.UpdateToAndIncrement(effect_output());
-    } else if (NodeProperties::IsControlEdge(iter.edge())) {
-      UNREACHABLE();
-    } else {
-      DCHECK(NodeProperties::IsValueEdge(iter.edge()));
-      iter.UpdateToAndIncrement(value_output());
-    }
-  }
+  NodeProperties::ReplaceWithValue(call, value_output(), effect_output());
   call->RemoveAllInputs();
   DCHECK_EQ(0, call->UseCount());
-  // TODO(sigurds) Remove this once we copy.
-  unique_return()->RemoveAllInputs();
 }
 
 
@@ -368,7 +361,7 @@ Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
 }
 
 
-void JSInliner::TryInlineCall(Node* call_node) {
+void JSInliner::TryInlineJSCall(Node* call_node) {
   JSCallFunctionAccessor call(call_node);
 
   HeapObjectMatcher<JSFunction> match(call.jsfunction());
@@ -391,7 +384,7 @@ void JSInliner::TryInlineCall(Node* call_node) {
   CompilationInfoWithZone info(function);
   Parse(function, &info);
 
-  if (info.scope()->arguments() != NULL) {
+  if (info.scope()->arguments() != NULL && info.strict_mode() != STRICT) {
     // For now do not inline functions that use their arguments array.
     SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
     if (FLAG_trace_turbo_inlining) {
@@ -440,6 +433,72 @@ void JSInliner::TryInlineCall(Node* call_node) {
 
   inlinee.InlineAtCall(jsgraph_, call_node);
 }
+
+
+class JSCallRuntimeAccessor {
+ public:
+  explicit JSCallRuntimeAccessor(Node* call) : call_(call) {
+    DCHECK_EQ(IrOpcode::kJSCallRuntime, call->opcode());
+  }
+
+  Node* formal_argument(size_t index) {
+    DCHECK(index < formal_arguments());
+    return call_->InputAt(static_cast<int>(index));
+  }
+
+  size_t formal_arguments() {
+    size_t value_inputs = OperatorProperties::GetValueInputCount(call_->op());
+    return value_inputs;
+  }
+
+  Node* frame_state() const {
+    return NodeProperties::GetFrameStateInput(call_);
+  }
+  Node* context() const { return NodeProperties::GetContextInput(call_); }
+  Node* control() const { return NodeProperties::GetControlInput(call_); }
+  Node* effect() const { return NodeProperties::GetEffectInput(call_); }
+
+  const Runtime::Function* function() const {
+    return Runtime::FunctionForId(OpParameter<Runtime::FunctionId>(call_));
+  }
+
+  NodeVector inputs(Zone* zone) const {
+    NodeVector inputs(zone);
+    for (InputIter it = call_->inputs().begin(); it != call_->inputs().end();
+         ++it) {
+      inputs.push_back(*it);
+    }
+    return inputs;
+  }
+
+ private:
+  Node* call_;
+};
+
+
+void JSInliner::TryInlineRuntimeCall(Node* call_node) {
+  JSCallRuntimeAccessor call(call_node);
+  const Runtime::Function* f = call.function();
+
+  if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) {
+    return;
+  }
+
+  JSIntrinsicBuilder intrinsic_builder(jsgraph_);
+
+  ResultAndEffect r = intrinsic_builder.BuildGraphFor(
+      f->function_id, call.inputs(jsgraph_->zone()));
+
+  if (r.first != NULL) {
+    if (FLAG_trace_turbo_inlining) {
+      PrintF("Inlining %s into %s\n", f->name,
+             info_->shared_info()->DebugName()->ToCString().get());
+    }
+    NodeProperties::ReplaceWithValue(call_node, r.first, r.second);
+    call_node->RemoveAllInputs();
+    DCHECK_EQ(0, call_node->UseCount());
+  }
+}
 }
 }
 }  // namespace v8::internal::compiler
index f135170..98cf3aa 100644 (file)
@@ -20,7 +20,8 @@ class JSInliner {
       : info_(info), jsgraph_(jsgraph) {}
 
   void Inline();
-  void TryInlineCall(Node* node);
+  void TryInlineJSCall(Node* node);
+  void TryInlineRuntimeCall(Node* node);
 
  private:
   friend class InlinerVisitor;
diff --git a/src/compiler/js-intrinsic-builder.cc b/src/compiler/js-intrinsic-builder.cc
new file mode 100644 (file)
index 0000000..4d8f607
--- /dev/null
@@ -0,0 +1,158 @@
+// 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/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/js-intrinsic-builder.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/simplified-operator.h"
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor(Runtime::FunctionId id,
+                                                  const NodeVector& arguments) {
+  switch (id) {
+    case Runtime::kInlineIsSmi:
+      return BuildGraphFor_IsSmi(arguments);
+    case Runtime::kInlineIsNonNegativeSmi:
+      return BuildGraphFor_IsNonNegativeSmi(arguments);
+    case Runtime::kInlineIsArray:
+      return BuildMapCheck(arguments[0], arguments[2], JS_ARRAY_TYPE);
+    case Runtime::kInlineIsRegExp:
+      return BuildMapCheck(arguments[0], arguments[2], JS_REGEXP_TYPE);
+    case Runtime::kInlineIsFunction:
+      return BuildMapCheck(arguments[0], arguments[2], JS_FUNCTION_TYPE);
+    case Runtime::kInlineValueOf:
+      return BuildGraphFor_ValueOf(arguments);
+    default:
+      break;
+  }
+  return ResultAndEffect();
+}
+
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_IsSmi(
+    const NodeVector& arguments) {
+  Node* object = arguments[0];
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+  Node* condition = graph()->NewNode(simplified.ObjectIsSmi(), object);
+
+  return ResultAndEffect(condition, arguments[2]);
+}
+
+
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_IsNonNegativeSmi(
+    const NodeVector& arguments) {
+  Node* object = arguments[0];
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+  Node* condition =
+      graph()->NewNode(simplified.ObjectIsNonNegativeSmi(), object);
+
+  return ResultAndEffect(condition, arguments[2]);
+}
+
+
+/*
+ * if (_isSmi(object)) {
+ *   return false
+ * } else {
+ *   return %_GetMapInstanceType(object) == map_type
+ * }
+ */
+ResultAndEffect JSIntrinsicBuilder::BuildMapCheck(Node* object, Node* effect,
+                                                  InstanceType map_type) {
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+
+  Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
+  Node* branch = graph()->NewNode(common()->Branch(), is_smi, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+
+  Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
+                               object, effect, if_false);
+
+  Node* instance_type = graph()->NewNode(
+      simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
+      if_false);
+
+  Node* has_map_type =
+      graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
+                       jsgraph_->Int32Constant(map_type));
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+
+  Node* phi =
+      graph()->NewNode(common()->Phi((MachineType)(kTypeBool | kRepTagged), 2),
+                       jsgraph_->FalseConstant(), has_map_type, merge);
+
+  Node* ephi =
+      graph()->NewNode(common()->EffectPhi(2), effect, instance_type, merge);
+
+  return ResultAndEffect(phi, ephi);
+}
+
+
+/*
+ * if (%_isSmi(object)) {
+ *   return object;
+ * } else if (%_GetMapInstanceType(object) == JS_VALUE_TYPE) {
+ *   return %_LoadValueField(object);
+ * } else {
+ *   return object;
+ * }
+ */
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_ValueOf(
+    const NodeVector& arguments) {
+  Node* object = arguments[0];
+  Node* effect = arguments[2];
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+
+  Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
+  Node* branch = graph()->NewNode(common()->Branch(), is_smi, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+
+  Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
+                               object, effect, if_false);
+
+  Node* instance_type = graph()->NewNode(
+      simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
+      if_false);
+
+  Node* is_value =
+      graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
+                       jsgraph_->Constant(JS_VALUE_TYPE));
+
+  Node* branch_is_value =
+      graph()->NewNode(common()->Branch(), is_value, if_false);
+  Node* is_value_true = graph()->NewNode(common()->IfTrue(), branch_is_value);
+  Node* is_value_false = graph()->NewNode(common()->IfFalse(), branch_is_value);
+
+  Node* value =
+      graph()->NewNode(simplified.LoadField(AccessBuilder::ForValue()), object,
+                       instance_type, is_value_true);
+
+  Node* merge_is_value =
+      graph()->NewNode(common()->Merge(2), is_value_true, is_value_false);
+
+  Node* phi_is_value = graph()->NewNode(common()->Phi((MachineType)kTypeAny, 2),
+                                        value, object, merge_is_value);
+
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, merge_is_value);
+
+  Node* phi = graph()->NewNode(common()->Phi((MachineType)kTypeAny, 2), object,
+                               phi_is_value, merge);
+
+  Node* ephi =
+      graph()->NewNode(common()->EffectPhi(2), effect, instance_type, merge);
+
+  return ResultAndEffect(phi, ephi);
+}
+}
+}
+}  // namespace v8::internal::compiler
diff --git a/src/compiler/js-intrinsic-builder.h b/src/compiler/js-intrinsic-builder.h
new file mode 100644 (file)
index 0000000..9336be6
--- /dev/null
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef V8_COMPILER_JS_INTRINSIC_BUILDER_H_
+#define V8_COMPILER_JS_INTRINSIC_BUILDER_H_
+
+#include "src/compiler/js-graph.h"
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef std::pair<Node*, Node*> ResultAndEffect;
+
+class JSIntrinsicBuilder {
+ public:
+  explicit JSIntrinsicBuilder(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
+
+  ResultAndEffect BuildGraphFor(Runtime::FunctionId id,
+                                const NodeVector& arguments);
+
+ private:
+  ResultAndEffect BuildMapCheck(Node* object, Node* effect,
+                                InstanceType map_type);
+  ResultAndEffect BuildGraphFor_IsSmi(const NodeVector& arguments);
+  ResultAndEffect BuildGraphFor_IsNonNegativeSmi(const NodeVector& arguments);
+  ResultAndEffect BuildGraphFor_ValueOf(const NodeVector& arguments);
+
+
+  Graph* graph() const { return jsgraph_->graph(); }
+  CommonOperatorBuilder* common() const { return jsgraph_->common(); }
+  JSGraph* jsgraph_;
+};
+}
+}
+}  // namespace v8::internal::compiler
+
+#endif  // V8_COMPILER_JS_INTRINSIC_BUILDER_H_
index cd59799..5b7bc68 100644 (file)
@@ -178,6 +178,12 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
     case Runtime::kThrow:
     case Runtime::kTypedArraySetFastCases:
     case Runtime::kTypedArrayInitializeFromArrayLike:
+    case Runtime::kDebugEvaluateGlobal:
+    case Runtime::kOwnKeys:
+    case Runtime::kGetOwnPropertyNames:
+    case Runtime::kIsPropertyEnumerable:
+    case Runtime::kGetPrototype:
+    case Runtime::kSparseJoinWithSeparator:
       return true;
     default:
       return false;
index ea8263d..8b68e60 100644 (file)
   V(LoadField)                \
   V(LoadElement)              \
   V(StoreField)               \
-  V(StoreElement)
+  V(StoreElement)             \
+  V(ObjectIsSmi)              \
+  V(ObjectIsNonNegativeSmi)
 
 // Opcodes for Machine-level operators.
 #define MACHINE_OP_LIST(V)    \
index 8db430e..ae65d16 100644 (file)
@@ -699,6 +699,39 @@ class RepresentationSelector {
         if (lower()) lowering->DoStoreElement(node);
         break;
       }
+      case IrOpcode::kObjectIsSmi: {
+        ProcessInput(node, 0, kMachAnyTagged);
+        SetOutput(node, kRepBit | kTypeBool);
+        if (lower()) {
+          Node* is_tagged = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordAnd(), node->InputAt(0),
+              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
+          Node* is_smi = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordEqual(), is_tagged,
+              jsgraph_->Int32Constant(kSmiTag));
+          DeferReplacement(node, is_smi);
+        }
+        break;
+      }
+      case IrOpcode::kObjectIsNonNegativeSmi: {
+        ProcessInput(node, 0, kMachAnyTagged);
+        SetOutput(node, kRepBit | kTypeBool);
+        if (lower()) {
+          Node* is_tagged = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordAnd(), node->InputAt(0),
+              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
+          Node* is_smi = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordEqual(), is_tagged,
+              jsgraph_->Int32Constant(kSmiTag));
+          Node* is_non_neg = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->IntLessThanOrEqual(),
+              jsgraph_->Int32Constant(0), node->InputAt(0));
+          Node* is_non_neg_smi = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->Word32And(), is_smi, is_non_neg);
+          DeferReplacement(node, is_non_neg_smi);
+        }
+        break;
+      }
 
       //------------------------------------------------------------------
       // Machine-level operators.
index fc1d464..fc8415f 100644 (file)
@@ -135,7 +135,9 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
   V(ChangeUint32ToTagged, Operator::kNoProperties, 1)  \
   V(ChangeFloat64ToTagged, Operator::kNoProperties, 1) \
   V(ChangeBoolToBit, Operator::kNoProperties, 1)       \
-  V(ChangeBitToBool, Operator::kNoProperties, 1)
+  V(ChangeBitToBool, Operator::kNoProperties, 1)       \
+  V(ObjectIsSmi, Operator::kNoProperties, 1)           \
+  V(ObjectIsNonNegativeSmi, Operator::kNoProperties, 1)
 
 
 #define ACCESS_OP_LIST(V)                                 \
index db29fd1..7e80fc3 100644 (file)
@@ -146,6 +146,9 @@ class SimplifiedOperatorBuilder FINAL {
   const Operator* ChangeBoolToBit();
   const Operator* ChangeBitToBool();
 
+  const Operator* ObjectIsSmi();
+  const Operator* ObjectIsNonNegativeSmi();
+
   const Operator* LoadField(const FieldAccess&);
   const Operator* StoreField(const FieldAccess&);
 
index fc71fd2..70f80cb 100644 (file)
@@ -1228,6 +1228,16 @@ Bounds Typer::Visitor::TypeStoreElement(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeObjectIsSmi(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeObjectIsNonNegativeSmi(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
 // Machine operators.
 
 Bounds Typer::Visitor::TypeLoad(Node* node) {
index 0400500..f2ad4ba 100644 (file)
@@ -486,6 +486,14 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
         CHECK(bounds(node).upper->Is(Type::Boolean()));
         break;
       }
+      case IrOpcode::kObjectIsSmi:
+        CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
+        CHECK(bounds(node).upper->Is(Type::Boolean()));
+        break;
+      case IrOpcode::kObjectIsNonNegativeSmi:
+        CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
+        CHECK(bounds(node).upper->Is(Type::Boolean()));
+        break;
 
       case IrOpcode::kChangeTaggedToInt32: {
         // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
index 83b0abf..2f291a4 100644 (file)
@@ -347,7 +347,10 @@ DEFINE_BOOL(context_specialization, false,
             "enable context specialization in TurboFan")
 DEFINE_BOOL(turbo_deoptimization, false, "enable deoptimization in TurboFan")
 DEFINE_BOOL(turbo_inlining, false, "enable inlining in TurboFan")
+DEFINE_BOOL(turbo_inlining_intrinsics, false,
+            "enable inlining of intrinsics in TurboFan")
 DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
+DEFINE_IMPLICATION(turbo_inlining_intrinsics, turbo_inlining)
 DEFINE_IMPLICATION(turbo_inlining, turbo_types)
 DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
 
index ad82fec..8656b98 100644 (file)
@@ -350,4 +350,101 @@ TEST(InlineNonStrictIntoStrict) {
 }
 
 
+TEST(InlineIntrinsicIsSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "var x = 42;"
+      "function bar(s,t) { return %_IsSmi(x); };"
+      "return bar;"
+      "})();",
+      CompilationInfo::kInliningEnabled |
+          CompilationInfo::kContextSpecializing |
+          CompilationInfo::kTypingEnabled);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsNonNegativeSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "var x = 42;"
+      "function bar(s,t) { return %_IsNonNegativeSmi(x); };"
+      "return bar;"
+      "})();",
+      CompilationInfo::kInliningEnabled |
+          CompilationInfo::kContextSpecializing |
+          CompilationInfo::kTypingEnabled);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsArray) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "var x = [1,2,3];"
+      "function bar(s,t) { return %_IsArray(x); };"
+      "return bar;"
+      "})();",
+      CompilationInfo::kInliningEnabled |
+          CompilationInfo::kContextSpecializing |
+          CompilationInfo::kTypingEnabled);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T2(
+      "(function () {"
+      "var x = 32;"
+      "function bar(s,t) { return %_IsArray(x); };"
+      "return bar;"
+      "})();",
+      CompilationInfo::kInliningEnabled |
+          CompilationInfo::kContextSpecializing |
+          CompilationInfo::kTypingEnabled);
+
+  T2.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T3(
+      "(function () {"
+      "var x = bar;"
+      "function bar(s,t) { return %_IsArray(x); };"
+      "return bar;"
+      "})();",
+      CompilationInfo::kInliningEnabled |
+          CompilationInfo::kContextSpecializing |
+          CompilationInfo::kTypingEnabled);
+
+  T3.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineWithArguments) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t,u) { AssertInlineCount(2); "
+      "    return foo.arguments.length == 3 && "
+      "           foo.arguments[0] == 13 && "
+      "           foo.arguments[1] == 14 && "
+      "           foo.arguments[2] == 15; "
+      "  }"
+      "  function bar() { return foo(13, 14, 15); };"
+      "  return bar;"
+      "}"
+      ")();",
+      CompilationInfo::kInliningEnabled |
+          CompilationInfo::kContextSpecializing |
+          CompilationInfo::kTypingEnabled);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
+}
+
 #endif  // V8_TURBOFAN_TARGET
index a1b5676..76cbb8f 100644 (file)
@@ -8,10 +8,12 @@
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
-
+uint32_t flags = CompilationInfo::kInliningEnabled;
 
 TEST(IsSmi) {
-  FunctionTester T("(function(a) { return %_IsSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -23,7 +25,9 @@ TEST(IsSmi) {
 
 
 TEST(IsNonNegativeSmi) {
-  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -35,7 +39,9 @@ TEST(IsNonNegativeSmi) {
 
 
 TEST(IsMinusZero) {
-  FunctionTester T("(function(a) { return %_IsMinusZero(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
 
   T.CheckFalse(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -47,7 +53,9 @@ TEST(IsMinusZero) {
 
 
 TEST(IsArray) {
-  FunctionTester T("(function(a) { return %_IsArray(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -61,7 +69,9 @@ TEST(IsArray) {
 
 
 TEST(IsObject) {
-  FunctionTester T("(function(a) { return %_IsObject(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -75,7 +85,9 @@ TEST(IsObject) {
 
 
 TEST(IsFunction) {
-  FunctionTester T("(function(a) { return %_IsFunction(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
 
   T.CheckTrue(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -89,7 +101,9 @@ TEST(IsFunction) {
 
 
 TEST(IsRegExp) {
-  FunctionTester T("(function(a) { return %_IsRegExp(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -103,7 +117,9 @@ TEST(IsRegExp) {
 
 
 TEST(ClassOf) {
-  FunctionTester T("(function(a) { return %_ClassOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
 
   T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
   T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
@@ -117,7 +133,9 @@ TEST(ClassOf) {
 
 
 TEST(ObjectEquals) {
-  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags);
   CompileRun("var o = {}");
 
   T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)"));
@@ -130,7 +148,9 @@ TEST(ObjectEquals) {
 
 
 TEST(ValueOf) {
-  FunctionTester T("(function(a) { return %_ValueOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ValueOf(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val("a"));
   T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))"));
@@ -140,7 +160,9 @@ TEST(ValueOf) {
 
 
 TEST(SetValueOf) {
-  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags);
 
   T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a"));
   T.CheckCall(T.Val(123), T.NewObject("(new Number)"), T.Val(123));
@@ -149,7 +171,9 @@ TEST(SetValueOf) {
 
 
 TEST(StringCharFromCode) {
-  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val(97));
   T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
@@ -158,7 +182,9 @@ TEST(StringCharFromCode) {
 
 
 TEST(StringCharAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })", flags);
 
   T.CheckCall(T.Val("e"), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val("f"), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -167,7 +193,10 @@ TEST(StringCharAt) {
 
 
 TEST(StringCharCodeAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })",
+                   flags);
 
   T.CheckCall(T.Val('e'), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val('f'), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -176,7 +205,9 @@ TEST(StringCharCodeAt) {
 
 
 TEST(StringAdd) {
-  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
 
   T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
@@ -185,7 +216,9 @@ TEST(StringAdd) {
 
 
 TEST(StringSubString) {
-  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
 
   T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0));
   T.CheckCall(T.Val("abb"), T.Val("aaabbb"), T.Val(2));
@@ -194,7 +227,9 @@ TEST(StringSubString) {
 
 
 TEST(StringCompare) {
-  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags);
 
   T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb"));
@@ -203,7 +238,10 @@ TEST(StringCompare) {
 
 
 TEST(CallFunction) {
-  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })",
+                   flags);
   CompileRun("function f(a,b,c) { return a + b + c + this.d; }");
 
   T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f"));
index 196df4f..028b5d5 100644 (file)
         '../../src/compiler/js-graph.h',
         '../../src/compiler/js-inlining.cc',
         '../../src/compiler/js-inlining.h',
+        '../../src/compiler/js-intrinsic-builder.cc',
+        '../../src/compiler/js-intrinsic-builder.h',
         '../../src/compiler/js-operator.cc',
         '../../src/compiler/js-operator.h',
         '../../src/compiler/js-typed-lowering.cc',