"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",
// 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};
// 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();
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);
#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"
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;
}
}
- // 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();
}
}
-void JSInliner::TryInlineCall(Node* call_node) {
+void JSInliner::TryInlineJSCall(Node* call_node) {
JSCallFunctionAccessor call(call_node);
HeapObjectMatcher<JSFunction> match(call.jsfunction());
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) {
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
: info_(info), jsgraph_(jsgraph) {}
void Inline();
- void TryInlineCall(Node* node);
+ void TryInlineJSCall(Node* node);
+ void TryInlineRuntimeCall(Node* node);
private:
friend class InlinerVisitor;
--- /dev/null
+// 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
--- /dev/null
+// 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_
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;
V(LoadField) \
V(LoadElement) \
V(StoreField) \
- V(StoreElement)
+ V(StoreElement) \
+ V(ObjectIsSmi) \
+ V(ObjectIsNonNegativeSmi)
// Opcodes for Machine-level operators.
#define MACHINE_OP_LIST(V) \
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.
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) \
const Operator* ChangeBoolToBit();
const Operator* ChangeBitToBool();
+ const Operator* ObjectIsSmi();
+ const Operator* ObjectIsNonNegativeSmi();
+
const Operator* LoadField(const FieldAccess&);
const Operator* StoreField(const FieldAccess&);
}
+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) {
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
"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")
}
+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
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));
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));
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));
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])"));
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])"));
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])"));
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])"));
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])"));
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)"));
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'))"));
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));
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));
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));
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));
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(""));
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));
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"));
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"));
'../../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',