Added %_HeapObjectGetMap and %_MapGetInstanceType intrinsics.

These are needed (among other things) for a TurboFan-generated
StringAddStub. Furthermore, they can be used to nuke the overly
complex %_IsInstanceType intrisic, it's completely expressible in
JavaScript now, but that will be done in a separate CL.

Alpha-sorted things a bit on the way to ease navigation.

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

Cr-Commit-Position: refs/heads/master@{#27415}
This commit is contained in:
svenpanne 2015-03-24 08:20:46 -07:00 committed by Commit bot
parent 4c806802b5
commit 20dce719ee
5 changed files with 241 additions and 168 deletions

View File

@ -1,3 +1,4 @@
// Copyright 2015 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.
@ -22,36 +23,40 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
switch (f->function_id) {
case Runtime::kInlineDeoptimizeNow:
return ReduceInlineDeoptimizeNow(node);
case Runtime::kInlineIsSmi:
return ReduceInlineIsSmi(node);
case Runtime::kInlineIsNonNegativeSmi:
return ReduceInlineIsNonNegativeSmi(node);
case Runtime::kInlineIsArray:
return ReduceInlineIsInstanceType(node, JS_ARRAY_TYPE);
case Runtime::kInlineIsFunction:
return ReduceInlineIsInstanceType(node, JS_FUNCTION_TYPE);
case Runtime::kInlineJSValueGetValue:
return ReduceInlineJSValueGetValue(node);
case Runtime::kInlineConstructDouble:
return ReduceInlineConstructDouble(node);
case Runtime::kInlineDoubleLo:
return ReduceInlineDoubleLo(node);
return ReduceConstructDouble(node);
case Runtime::kInlineDeoptimizeNow:
return ReduceDeoptimizeNow(node);
case Runtime::kInlineDoubleHi:
return ReduceInlineDoubleHi(node);
return ReduceDoubleHi(node);
case Runtime::kInlineDoubleLo:
return ReduceDoubleLo(node);
case Runtime::kInlineHeapObjectGetMap:
return ReduceHeapObjectGetMap(node);
case Runtime::kInlineIsArray:
return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
case Runtime::kInlineIsFunction:
return ReduceIsInstanceType(node, JS_FUNCTION_TYPE);
case Runtime::kInlineIsNonNegativeSmi:
return ReduceIsNonNegativeSmi(node);
case Runtime::kInlineIsRegExp:
return ReduceInlineIsInstanceType(node, JS_REGEXP_TYPE);
return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
case Runtime::kInlineIsSmi:
return ReduceIsSmi(node);
case Runtime::kInlineJSValueGetValue:
return ReduceJSValueGetValue(node);
case Runtime::kInlineMapGetInstanceType:
return ReduceMapGetInstanceType(node);
case Runtime::kInlineMathClz32:
return ReduceInlineMathClz32(node);
return ReduceMathClz32(node);
case Runtime::kInlineMathFloor:
return ReduceInlineMathFloor(node);
return ReduceMathFloor(node);
case Runtime::kInlineMathSqrt:
return ReduceInlineMathSqrt(node);
return ReduceMathSqrt(node);
case Runtime::kInlineStringGetLength:
return ReduceInlineStringGetLength(node);
return ReduceStringGetLength(node);
case Runtime::kInlineValueOf:
return ReduceInlineValueOf(node);
return ReduceValueOf(node);
default:
break;
}
@ -59,7 +64,20 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
}
Reduction JSIntrinsicLowering::ReduceInlineDeoptimizeNow(Node* node) {
Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
Node* high = NodeProperties::GetValueInput(node, 0);
Node* low = NodeProperties::GetValueInput(node, 1);
Node* value =
graph()->NewNode(machine()->Float64InsertHighWord32(),
graph()->NewNode(machine()->Float64InsertLowWord32(),
jsgraph()->Constant(0), low),
high);
NodeProperties::ReplaceWithValue(node, value);
return Replace(value);
}
Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
if (!FLAG_turbo_deoptimization) return NoChange();
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
@ -99,49 +117,26 @@ Reduction JSIntrinsicLowering::ReduceInlineDeoptimizeNow(Node* node) {
}
Reduction JSIntrinsicLowering::ReduceInlineIsSmi(Node* node) {
return Change(node, simplified()->ObjectIsSmi());
}
Reduction JSIntrinsicLowering::ReduceInlineIsNonNegativeSmi(Node* node) {
return Change(node, simplified()->ObjectIsNonNegativeSmi());
}
Reduction JSIntrinsicLowering::ReduceInlineJSValueGetValue(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node, simplified()->LoadField(AccessBuilder::ForValue()), value,
effect, control);
}
Reduction JSIntrinsicLowering::ReduceInlineConstructDouble(Node* node) {
Node* high = NodeProperties::GetValueInput(node, 0);
Node* low = NodeProperties::GetValueInput(node, 1);
Node* value =
graph()->NewNode(machine()->Float64InsertHighWord32(),
graph()->NewNode(machine()->Float64InsertLowWord32(),
jsgraph()->Constant(0), low),
high);
NodeProperties::ReplaceWithValue(node, value);
return Replace(value);
}
Reduction JSIntrinsicLowering::ReduceInlineDoubleLo(Node* node) {
return Change(node, machine()->Float64ExtractLowWord32());
}
Reduction JSIntrinsicLowering::ReduceInlineDoubleHi(Node* node) {
Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
return Change(node, machine()->Float64ExtractHighWord32());
}
Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType(
Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
return Change(node, machine()->Float64ExtractLowWord32());
}
Reduction JSIntrinsicLowering::ReduceHeapObjectGetMap(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node, simplified()->LoadField(AccessBuilder::ForMap()), value,
effect, control);
}
Reduction JSIntrinsicLowering::ReduceIsInstanceType(
Node* node, InstanceType instance_type) {
// if (%_IsSmi(value)) {
// return false;
@ -181,23 +176,52 @@ Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType(
}
Reduction JSIntrinsicLowering::ReduceInlineMathClz32(Node* node) {
Reduction JSIntrinsicLowering::ReduceIsNonNegativeSmi(Node* node) {
return Change(node, simplified()->ObjectIsNonNegativeSmi());
}
Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
return Change(node, simplified()->ObjectIsSmi());
}
Reduction JSIntrinsicLowering::ReduceJSValueGetValue(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node, simplified()->LoadField(AccessBuilder::ForValue()), value,
effect, control);
}
Reduction JSIntrinsicLowering::ReduceMapGetInstanceType(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
return Change(node,
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
value, effect, control);
}
Reduction JSIntrinsicLowering::ReduceMathClz32(Node* node) {
return Change(node, machine()->Word32Clz());
}
Reduction JSIntrinsicLowering::ReduceInlineMathFloor(Node* node) {
Reduction JSIntrinsicLowering::ReduceMathFloor(Node* node) {
if (!machine()->HasFloat64RoundDown()) return NoChange();
return Change(node, machine()->Float64RoundDown());
}
Reduction JSIntrinsicLowering::ReduceInlineMathSqrt(Node* node) {
Reduction JSIntrinsicLowering::ReduceMathSqrt(Node* node) {
return Change(node, machine()->Float64Sqrt());
}
Reduction JSIntrinsicLowering::ReduceInlineStringGetLength(Node* node) {
Reduction JSIntrinsicLowering::ReduceStringGetLength(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
@ -206,7 +230,7 @@ Reduction JSIntrinsicLowering::ReduceInlineStringGetLength(Node* node) {
}
Reduction JSIntrinsicLowering::ReduceInlineValueOf(Node* node) {
Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
// if (%_IsSmi(value)) {
// return value;
// } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {

View File

@ -27,19 +27,21 @@ class JSIntrinsicLowering FINAL : public Reducer {
Reduction Reduce(Node* node) FINAL;
private:
Reduction ReduceInlineDeoptimizeNow(Node* node);
Reduction ReduceInlineIsSmi(Node* node);
Reduction ReduceInlineIsNonNegativeSmi(Node* node);
Reduction ReduceInlineIsInstanceType(Node* node, InstanceType instance_type);
Reduction ReduceInlineJSValueGetValue(Node* node);
Reduction ReduceInlineConstructDouble(Node* node);
Reduction ReduceInlineDoubleLo(Node* node);
Reduction ReduceInlineDoubleHi(Node* node);
Reduction ReduceInlineMathClz32(Node* node);
Reduction ReduceInlineMathFloor(Node* node);
Reduction ReduceInlineMathSqrt(Node* node);
Reduction ReduceInlineStringGetLength(Node* node);
Reduction ReduceInlineValueOf(Node* node);
Reduction ReduceConstructDouble(Node* node);
Reduction ReduceDeoptimizeNow(Node* node);
Reduction ReduceDoubleHi(Node* node);
Reduction ReduceDoubleLo(Node* node);
Reduction ReduceHeapObjectGetMap(Node* node);
Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type);
Reduction ReduceIsNonNegativeSmi(Node* node);
Reduction ReduceIsSmi(Node* node);
Reduction ReduceJSValueGetValue(Node* node);
Reduction ReduceMapGetInstanceType(Node* node);
Reduction ReduceMathClz32(Node* node);
Reduction ReduceMathFloor(Node* node);
Reduction ReduceMathSqrt(Node* node);
Reduction ReduceStringGetLength(Node* node);
Reduction ReduceValueOf(Node* node);
Reduction Change(Node* node, const Operator* op);
Reduction Change(Node* node, const Operator* op, Node* a, Node* b, Node* c);

View File

@ -1506,6 +1506,22 @@ RUNTIME_FUNCTION(Runtime_JSValueGetValue) {
}
RUNTIME_FUNCTION(Runtime_HeapObjectGetMap) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(HeapObject, obj, 0);
return obj->map();
}
RUNTIME_FUNCTION(Runtime_MapGetInstanceType) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Map, map, 0);
return Smi::FromInt(map->instance_type());
}
RUNTIME_FUNCTION(Runtime_ObjectEquals) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);

View File

@ -718,7 +718,11 @@ namespace internal {
/* Strings */ \
F(StringGetLength, 1, 1) \
/* JSValue */ \
F(JSValueGetValue, 1, 1)
F(JSValueGetValue, 1, 1) \
/* HeapObject */ \
F(HeapObjectGetMap, 1, 1) \
/* Map */ \
F(MapGetInstanceType, 1, 1)
#define FOR_EACH_INTRINSIC_RETURN_OBJECT(F) \

View File

@ -10,42 +10,42 @@ using namespace v8::internal;
using namespace v8::internal::compiler;
uint32_t flags = CompilationInfo::kInliningEnabled;
TEST(IsSmi) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
T.CheckTrue(T.Val(1));
T.CheckFalse(T.Val(1.1));
T.CheckFalse(T.Val(-0.0));
T.CheckTrue(T.Val(-2));
T.CheckFalse(T.Val(-2.3));
T.CheckFalse(T.undefined());
TEST(CallFunction) {
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"));
T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f"));
}
TEST(IsNonNegativeSmi) {
TEST(ClassOf) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
T.CheckTrue(T.Val(1));
T.CheckFalse(T.Val(1.1));
T.CheckFalse(T.Val(-0.0));
T.CheckFalse(T.Val(-2));
T.CheckFalse(T.Val(-2.3));
T.CheckFalse(T.undefined());
T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
T.CheckCall(T.Val("Object"), T.NewObject("({})"));
T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)"));
T.CheckCall(T.null(), T.undefined());
T.CheckCall(T.null(), T.null());
T.CheckCall(T.null(), T.Val("x"));
T.CheckCall(T.null(), T.Val(1));
}
TEST(IsMinusZero) {
TEST(HeapObjectGetMap) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
FunctionTester T("(function(a) { return %_HeapObjectGetMap(a); })", flags);
T.CheckFalse(T.Val(1));
T.CheckFalse(T.Val(1.1));
T.CheckTrue(T.Val(-0.0));
T.CheckFalse(T.Val(-2));
T.CheckFalse(T.Val(-2.3));
T.CheckFalse(T.undefined());
Factory* factory = T.main_isolate()->factory();
T.CheckCall(factory->null_map(), T.null());
T.CheckCall(factory->undefined_map(), T.undefined());
T.CheckCall(factory->heap_number_map(), T.Val(3.1415));
T.CheckCall(factory->symbol_map(), factory->NewSymbol());
}
@ -64,21 +64,6 @@ TEST(IsArray) {
}
TEST(IsObject) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
T.CheckFalse(T.NewObject("(function() {})"));
T.CheckTrue(T.NewObject("([1])"));
T.CheckTrue(T.NewObject("({})"));
T.CheckTrue(T.NewObject("(/x/)"));
T.CheckFalse(T.undefined());
T.CheckTrue(T.null());
T.CheckFalse(T.Val("x"));
T.CheckFalse(T.Val(1));
}
TEST(IsFunction) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
@ -94,6 +79,47 @@ TEST(IsFunction) {
}
TEST(IsMinusZero) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
T.CheckFalse(T.Val(1));
T.CheckFalse(T.Val(1.1));
T.CheckTrue(T.Val(-0.0));
T.CheckFalse(T.Val(-2));
T.CheckFalse(T.Val(-2.3));
T.CheckFalse(T.undefined());
}
TEST(IsNonNegativeSmi) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
T.CheckTrue(T.Val(1));
T.CheckFalse(T.Val(1.1));
T.CheckFalse(T.Val(-0.0));
T.CheckFalse(T.Val(-2));
T.CheckFalse(T.Val(-2.3));
T.CheckFalse(T.undefined());
}
TEST(IsObject) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
T.CheckFalse(T.NewObject("(function() {})"));
T.CheckTrue(T.NewObject("([1])"));
T.CheckTrue(T.NewObject("({})"));
T.CheckTrue(T.NewObject("(/x/)"));
T.CheckFalse(T.undefined());
T.CheckTrue(T.null());
T.CheckFalse(T.Val("x"));
T.CheckFalse(T.Val(1));
}
TEST(IsRegExp) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
@ -109,18 +135,30 @@ TEST(IsRegExp) {
}
TEST(ClassOf) {
TEST(IsSmi) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
T.CheckCall(T.Val("Object"), T.NewObject("({})"));
T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)"));
T.CheckCall(T.null(), T.undefined());
T.CheckCall(T.null(), T.null());
T.CheckCall(T.null(), T.Val("x"));
T.CheckCall(T.null(), T.Val(1));
T.CheckTrue(T.Val(1));
T.CheckFalse(T.Val(1.1));
T.CheckFalse(T.Val(-0.0));
T.CheckTrue(T.Val(-2));
T.CheckFalse(T.Val(-2.3));
T.CheckFalse(T.undefined());
}
TEST(MapGetInstanceType) {
FLAG_turbo_deoptimization = true;
FunctionTester T(
"(function(a) { return %_MapGetInstanceType(%_HeapObjectGetMap(a)); })",
flags);
Factory* factory = T.main_isolate()->factory();
T.CheckCall(T.Val(ODDBALL_TYPE), T.null());
T.CheckCall(T.Val(ODDBALL_TYPE), T.undefined());
T.CheckCall(T.Val(HEAP_NUMBER_TYPE), T.Val(3.1415));
T.CheckCall(T.Val(SYMBOL_TYPE), factory->NewSymbol());
}
@ -138,17 +176,6 @@ TEST(ObjectEquals) {
}
TEST(ValueOf) {
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'))"));
T.CheckCall(T.Val(123), T.Val(123));
T.CheckCall(T.Val(456), T.NewObject("(new Number(456))"));
}
TEST(SetValueOf) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags);
@ -159,13 +186,13 @@ TEST(SetValueOf) {
}
TEST(StringCharFromCode) {
TEST(StringAdd) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
T.CheckCall(T.Val("a"), T.Val(97));
T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
T.CheckCall(T.Val(""), T.undefined());
T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb"));
}
@ -190,23 +217,13 @@ TEST(StringCharCodeAt) {
}
TEST(StringAdd) {
TEST(StringCharFromCode) {
FLAG_turbo_deoptimization = true;
FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb"));
}
TEST(StringSubString) {
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));
T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(0.0));
T.CheckCall(T.Val("a"), T.Val(97));
T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
T.CheckCall(T.Val(""), T.undefined());
}
@ -220,12 +237,22 @@ TEST(StringCompare) {
}
TEST(CallFunction) {
TEST(SubString) {
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; }");
FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f"));
T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f"));
T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0));
T.CheckCall(T.Val("abb"), T.Val("aaabbb"), T.Val(2));
T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(0.0));
}
TEST(ValueOf) {
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'))"));
T.CheckCall(T.Val(123), T.Val(123));
T.CheckCall(T.Val(456), T.NewObject("(new Number(456))"));
}