From 350a70e5ef4262baf912f09389f1eb1d1aa9f842 Mon Sep 17 00:00:00 2001 From: littledan Date: Mon, 15 Jun 2015 15:16:33 -0700 Subject: [PATCH] Inline code generation for %_IsTypedArray This patch implements %_IsTypedArray in fullcodegen, Hydrogen and Turbofan in order to implement fast type checks to enable ES6 TypedArray features and semantics efficiently. R=adamk,titzer LOG=Y BUG=v8:4085 Review URL: https://codereview.chromium.org/1183213002 Cr-Commit-Position: refs/heads/master@{#29033} --- src/arm/full-codegen-arm.cc | 22 ++++++++++++ src/arm64/full-codegen-arm64.cc | 22 ++++++++++++ src/compiler/js-intrinsic-lowering.cc | 2 ++ src/compiler/typer.cc | 1 + src/full-codegen.h | 1 + src/harmony-typedarray.js | 36 +++++++++---------- src/hydrogen.cc | 10 ++++++ src/hydrogen.h | 1 + src/ia32/full-codegen-ia32.cc | 23 +++++++++++- src/mips/full-codegen-mips.cc | 22 ++++++++++++ src/mips64/full-codegen-mips64.cc | 22 ++++++++++++ src/ppc/full-codegen-ppc.cc | 22 ++++++++++++ src/typedarray.js | 2 +- src/x64/full-codegen-x64.cc | 22 ++++++++++++ src/x87/full-codegen-x87.cc | 23 +++++++++++- .../js-intrinsic-lowering-unittest.cc | 31 ++++++++++++++++ 16 files changed, 241 insertions(+), 21 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index a2f24400a4..f5b90b60bd 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -3650,6 +3650,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r1, r1, JS_TYPED_ARRAY_TYPE); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(eq, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 454bf03ddc..2cf7142943 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -3350,6 +3350,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(x0, if_false); + __ CompareObjectType(x0, x10, x11, JS_TYPED_ARRAY_TYPE); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(eq, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc index 891e17fb37..2c86ab78c0 100644 --- a/src/compiler/js-intrinsic-lowering.cc +++ b/src/compiler/js-intrinsic-lowering.cc @@ -46,6 +46,8 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { return ReduceIncrementStatsCounter(node); case Runtime::kInlineIsArray: return ReduceIsInstanceType(node, JS_ARRAY_TYPE); + case Runtime::kInlineIsTypedArray: + return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE); case Runtime::kInlineIsFunction: return ReduceIsInstanceType(node, JS_FUNCTION_TYPE); case Runtime::kInlineIsNonNegativeSmi: diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index aeacad5e42..94b9d6d1bb 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -1599,6 +1599,7 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { case Runtime::kInlineIsSmi: case Runtime::kInlineIsNonNegativeSmi: case Runtime::kInlineIsArray: + case Runtime::kInlineIsTypedArray: case Runtime::kInlineIsMinusZero: case Runtime::kInlineIsFunction: case Runtime::kInlineIsRegExp: diff --git a/src/full-codegen.h b/src/full-codegen.h index ecab4f9bc0..4492434942 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -521,6 +521,7 @@ class FullCodeGenerator: public AstVisitor { F(IsSmi) \ F(IsNonNegativeSmi) \ F(IsArray) \ + F(IsTypedArray) \ F(IsRegExp) \ F(IsJSProxy) \ F(IsConstructCall) \ diff --git a/src/harmony-typedarray.js b/src/harmony-typedarray.js index 7d9006fb9e..b9cc798ad2 100644 --- a/src/harmony-typedarray.js +++ b/src/harmony-typedarray.js @@ -104,7 +104,7 @@ function ConstructTypedArrayLike(typedArray, arg) { } function TypedArrayCopyWithin(target, start, end) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -115,7 +115,7 @@ function TypedArrayCopyWithin(target, start, end) { // ES6 draft 05-05-15, section 22.2.3.7 function TypedArrayEvery(f, receiver) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -125,7 +125,7 @@ function TypedArrayEvery(f, receiver) { // ES6 draft 08-24-14, section 22.2.3.12 function TypedArrayForEach(f, receiver) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -135,7 +135,7 @@ function TypedArrayForEach(f, receiver) { // ES6 draft 04-05-14 section 22.2.3.8 function TypedArrayFill(value, start, end) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -145,7 +145,7 @@ function TypedArrayFill(value, start, end) { // ES6 draft 07-15-13, section 22.2.3.9 function TypedArrayFilter(predicate, thisArg) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); var array = InnerArrayFilter(predicate, thisArg, this, length); @@ -155,7 +155,7 @@ function TypedArrayFilter(predicate, thisArg) { // ES6 draft 07-15-13, section 22.2.3.10 function TypedArrayFind(predicate, thisArg) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -165,7 +165,7 @@ function TypedArrayFind(predicate, thisArg) { // ES6 draft 07-15-13, section 22.2.3.11 function TypedArrayFindIndex(predicate, thisArg) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -175,7 +175,7 @@ function TypedArrayFindIndex(predicate, thisArg) { // ES6 draft 05-18-15, section 22.2.3.21 function TypedArrayReverse() { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -205,7 +205,7 @@ function TypedArrayComparefn(x, y) { // ES6 draft 05-18-15, section 22.2.3.25 function TypedArraySort(comparefn) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -219,7 +219,7 @@ function TypedArraySort(comparefn) { // ES6 section 22.2.3.13 function TypedArrayIndexOf(element, index) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -230,7 +230,7 @@ function TypedArrayIndexOf(element, index) { // ES6 section 22.2.3.16 function TypedArrayLastIndexOf(element, index) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -242,7 +242,7 @@ function TypedArrayLastIndexOf(element, index) { // ES6 draft 07-15-13, section 22.2.3.18 function TypedArrayMap(predicate, thisArg) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); // TODO(littledan): Preallocate rather than making an intermediate // InternalArray, for better performance. @@ -255,7 +255,7 @@ function TypedArrayMap(predicate, thisArg) { // ES6 draft 05-05-15, section 22.2.3.24 function TypedArraySome(f, receiver) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -266,7 +266,7 @@ function TypedArraySome(f, receiver) { // ES6 section 22.2.3.27 function TypedArrayToLocaleString() { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -282,7 +282,7 @@ function TypedArrayToString() { // ES6 section 22.2.3.14 function TypedArrayJoin(separator) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); @@ -292,7 +292,7 @@ function TypedArrayJoin(separator) { // ES6 draft 07-15-13, section 22.2.3.19 function TypedArrayReduce(callback, current) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); return InnerArrayReduce(callback, current, this, length, @@ -303,7 +303,7 @@ function TypedArrayReduce(callback, current) { // ES6 draft 07-15-13, section 22.2.3.19 function TypedArrayReduceRight(callback, current) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var length = %_TypedArrayGetLength(this); return InnerArrayReduceRight(callback, current, this, length, @@ -313,7 +313,7 @@ function TypedArrayReduceRight(callback, current) { function TypedArraySlice(start, end) { - if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); + if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); var len = %_TypedArrayGetLength(this); var relativeStart = TO_INTEGER(start); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index ecf05f4bc5..12decb0a23 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -11758,6 +11758,16 @@ void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) { } +void HOptimizedGraphBuilder::GenerateIsTypedArray(CallRuntime* call) { + DCHECK(call->arguments()->length() == 1); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + HValue* value = Pop(); + HHasInstanceTypeAndBranch* result = + New(value, JS_TYPED_ARRAY_TYPE); + return ast_context()->ReturnControl(result, call->id()); +} + + void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) { DCHECK(call->arguments()->length() == 1); CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); diff --git a/src/hydrogen.h b/src/hydrogen.h index 22c3bfa5c0..ad98f7c074 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2171,6 +2171,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { #define FOR_EACH_HYDROGEN_INTRINSIC(F) \ F(IsSmi) \ F(IsArray) \ + F(IsTypedArray) \ F(IsRegExp) \ F(IsJSProxy) \ F(IsConstructCall) \ diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 202740b385..f27dd21d5a 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -3513,7 +3513,6 @@ void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) { } - void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -3536,6 +3535,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, JS_TYPED_ARRAY_TYPE, ebx); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(equal, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 2440f98383..a44e02dee4 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -3627,6 +3627,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, a1, a1); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(eq, a1, Operand(JS_TYPED_ARRAY_TYPE), if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index 572b5b3a77..e608013f2f 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc @@ -3630,6 +3630,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, a1, a1); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(eq, a1, Operand(JS_TYPED_ARRAY_TYPE), if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/ppc/full-codegen-ppc.cc b/src/ppc/full-codegen-ppc.cc index ebd7efe8fb..2e34d163a2 100644 --- a/src/ppc/full-codegen-ppc.cc +++ b/src/ppc/full-codegen-ppc.cc @@ -3656,6 +3656,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(r3, if_false); + __ CompareObjectType(r3, r4, r4, JS_TYPED_ARRAY_TYPE); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(eq, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/typedarray.js b/src/typedarray.js index 2da7af0fa3..ce52cdf15c 100644 --- a/src/typedarray.js +++ b/src/typedarray.js @@ -339,7 +339,7 @@ function TypedArraySet(obj, offset) { } function TypedArrayGetToStringTag() { - if (!%IsTypedArray(this)) return; + if (!%_IsTypedArray(this)) return; var name = %_ClassOf(this); if (IS_UNDEFINED(name)) return; return name; diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index ed29faf4ed..7560117c73 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -3526,6 +3526,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, JS_TYPED_ARRAY_TYPE, rbx); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(equal, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index e2abd9d311..9798a50a4c 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -3504,7 +3504,6 @@ void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) { } - void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -3527,6 +3526,28 @@ void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { + ZoneList* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, JS_TYPED_ARRAY_TYPE, ebx); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(equal, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); diff --git a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc index d8380036d4..4c99654a68 100644 --- a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -173,6 +173,37 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsArray) { } +// ----------------------------------------------------------------------------- +// %_IsTypedArray + + +TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineIsTypedArray, 1), input, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + + Node* phi = r.replacement(); + Capture branch, if_false; + EXPECT_THAT( + phi, + IsPhi( + static_cast(kTypeBool | kRepTagged), IsFalseConstant(), + IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(), + IsLoadField(AccessBuilder::ForMap(), input, + effect, CaptureEq(&if_false)), + effect, _), + IsInt32Constant(JS_TYPED_ARRAY_TYPE)), + IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), + IsBranch(IsObjectIsSmi(input), control))), + AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); +} + + // ----------------------------------------------------------------------------- // %_IsFunction