From: bmeurer Date: Thu, 13 Aug 2015 13:06:45 +0000 (-0700) Subject: Revert of [runtime] Remove useless IN builtin. (patchset #2 id:20001 of https://coder... X-Git-Tag: upstream/4.7.83~885 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=96e331e2f2c43d53eb475766163b14b093efa4c0;p=platform%2Fupstream%2Fv8.git Revert of [runtime] Remove useless IN builtin. (patchset #2 id:20001 of https://codereview.chromium.org/1295433002/ ) Reason for revert: Breaks win32 nosnap Original issue's description: > [runtime] Remove useless IN builtin. > > Similar to DELETE, the IN builtin is just a thin wrapper for %HasElement > and %HasProperty anyway, and cannot be optimized, plus it had a weird > special fast case (which also involved at least one LOAD_IC plus some > intrinsic magic). > > R=yangguo@chromium.org,jarin@chromium.org > > Committed: https://crrev.com/72d60a1e80e81e2e68ca402665e2acbc46c5e471 > Cr-Commit-Position: refs/heads/master@{#30154} TBR=yangguo@chromium.org,jarin@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true Review URL: https://codereview.chromium.org/1288923002 Cr-Commit-Position: refs/heads/master@{#30155} --- diff --git a/src/builtins.h b/src/builtins.h index 816fc2b13..6ec618ada 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -175,6 +175,7 @@ enum BuiltinExtraArguments { V(SAR_STRONG, 1) \ V(SHR, 1) \ V(SHR_STRONG, 1) \ + V(IN, 1) \ V(INSTANCE_OF, 1) \ V(CALL_NON_FUNCTION, 0) \ V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \ diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 6691c758f..bec199e0e 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -437,7 +437,7 @@ void JSGenericLowering::LowerJSDeleteProperty(Node* node) { void JSGenericLowering::LowerJSHasProperty(Node* node) { - ReplaceWithRuntimeCall(node, Runtime::kHasProperty); + ReplaceWithBuiltinCall(node, Builtins::IN, 2); } diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc index 491795326..e82ac205c 100644 --- a/src/compiler/js-intrinsic-lowering.cc +++ b/src/compiler/js-intrinsic-lowering.cc @@ -52,6 +52,8 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE); case Runtime::kInlineIsFunction: return ReduceIsInstanceType(node, JS_FUNCTION_TYPE); + case Runtime::kInlineIsNonNegativeSmi: + return ReduceIsNonNegativeSmi(node); case Runtime::kInlineIsRegExp: return ReduceIsInstanceType(node, JS_REGEXP_TYPE); case Runtime::kInlineIsSmi: @@ -237,6 +239,11 @@ Reduction JSIntrinsicLowering::ReduceIsInstanceType( } +Reduction JSIntrinsicLowering::ReduceIsNonNegativeSmi(Node* node) { + return Change(node, simplified()->ObjectIsNonNegativeSmi()); +} + + Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) { return Change(node, simplified()->ObjectIsSmi()); } diff --git a/src/compiler/js-intrinsic-lowering.h b/src/compiler/js-intrinsic-lowering.h index 15e9b4053..c14882c73 100644 --- a/src/compiler/js-intrinsic-lowering.h +++ b/src/compiler/js-intrinsic-lowering.h @@ -41,6 +41,7 @@ class JSIntrinsicLowering final : public AdvancedReducer { Reduction ReduceIncrementStatsCounter(Node* node); Reduction ReduceIsMinusZero(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); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 101712ba0..aabcf4b5a 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -1535,6 +1535,7 @@ Bounds Typer::Visitor::TypeJSCallFunction(Node* node) { Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { switch (CallRuntimeParametersOf(node->op()).id()) { case Runtime::kInlineIsSmi: + case Runtime::kInlineIsNonNegativeSmi: case Runtime::kInlineIsArray: case Runtime::kInlineIsDate: case Runtime::kInlineIsTypedArray: diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index 27c362d93..d7a9bc3e5 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -3350,6 +3350,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + __ NonNegativeSmiTst(r0); + Split(eq, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5065,7 +5086,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ LoadRoot(ip, Heap::kTrueValueRootIndex); __ cmp(r0, ip); diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index c73c737e2..9e7334001 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -3043,6 +3043,28 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + uint64_t sign_mask = V8_UINT64_C(1) << (kSmiShift + kSmiValueSize - 1); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + __ TestAndSplit(x0, kSmiTagMask | sign_mask, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -4769,7 +4791,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ CompareRoot(x0, Heap::kTrueValueRootIndex); Split(eq, if_true, if_false, fall_through); diff --git a/src/full-codegen/full-codegen.h b/src/full-codegen/full-codegen.h index bb3e6fde6..846a6afec 100644 --- a/src/full-codegen/full-codegen.h +++ b/src/full-codegen/full-codegen.h @@ -488,6 +488,7 @@ class FullCodeGenerator: public AstVisitor { #define FOR_EACH_FULL_CODE_INTRINSIC(F) \ F(IsSmi) \ + F(IsNonNegativeSmi) \ F(IsArray) \ F(IsTypedArray) \ F(IsRegExp) \ diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index a0f3b6f9b..390a44be3 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -3243,6 +3243,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + __ test(eax, Immediate(kSmiTagMask | 0x80000000)); + Split(zero, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5004,7 +5025,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ cmp(eax, isolate()->factory()->true_value()); Split(equal, if_true, if_false, fall_through); diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index 0d655162f..d3139a7d4 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -3341,6 +3341,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + __ NonNegativeSmiTst(v0, at); + Split(eq, at, Operand(zero_reg), if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5090,7 +5111,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ LoadRoot(t0, Heap::kTrueValueRootIndex); Split(eq, v0, Operand(t0), if_true, if_false, fall_through); diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index 1cb2f1066..e8a46c3fa 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -3342,6 +3342,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + __ NonNegativeSmiTst(v0, at); + Split(eq, at, Operand(zero_reg), if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5092,7 +5113,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ LoadRoot(a4, Heap::kTrueValueRootIndex); Split(eq, v0, Operand(a4), if_true, if_false, fall_through); diff --git a/src/full-codegen/ppc/full-codegen-ppc.cc b/src/full-codegen/ppc/full-codegen-ppc.cc index 28edd4752..c92d883ef 100644 --- a/src/full-codegen/ppc/full-codegen-ppc.cc +++ b/src/full-codegen/ppc/full-codegen-ppc.cc @@ -3342,6 +3342,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + __ TestIfPositiveSmi(r3, r0); + Split(eq, if_true, if_false, fall_through, cr0); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5111,7 +5132,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ LoadRoot(ip, Heap::kTrueValueRootIndex); __ cmp(r3, ip); diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 354b52bcf..eda520702 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -3235,6 +3235,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); + Split(non_negative_smi, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5013,7 +5034,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ CompareRoot(rax, Heap::kTrueValueRootIndex); Split(equal, if_true, if_false, fall_through); diff --git a/src/full-codegen/x87/full-codegen-x87.cc b/src/full-codegen/x87/full-codegen-x87.cc index a7d4d5077..061954729 100644 --- a/src/full-codegen/x87/full-codegen-x87.cc +++ b/src/full-codegen/x87/full-codegen-x87.cc @@ -3234,6 +3234,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsNonNegativeSmi(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); + + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + __ test(eax, Immediate(kSmiTagMask | 0x80000000)); + Split(zero, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + + void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { ZoneList* args = expr->arguments(); DCHECK(args->length() == 1); @@ -5021,7 +5042,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { switch (op) { case Token::IN: VisitForStackValue(expr->right()); - __ CallRuntime(Runtime::kHasProperty, 2); + __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); __ cmp(eax, isolate()->factory()->true_value()); Split(equal, if_true, if_false, fall_through); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index efc47b611..d5868f399 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -11360,10 +11360,11 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { return ast_context()->ReturnInstruction(result, expr->id()); } else if (op == Token::IN) { + HValue* function = AddLoadJSBuiltin(Builtins::IN); Add(left, right); - HInstruction* result = - New(isolate()->factory()->empty_string(), - Runtime::FunctionForId(Runtime::kHasProperty), 2); + // TODO(olivf) InvokeFunction produces a check for the parameter count, + // even though we are certain to pass the correct number of arguments here. + HInstruction* result = New(function, 2); return ast_context()->ReturnInstruction(result, expr->id()); } diff --git a/src/runtime.js b/src/runtime.js index 25825d781..f7c91d3cc 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -44,6 +44,7 @@ var SAR; var SAR_STRONG; var SHR; var SHR_STRONG; +var IN; var INSTANCE_OF; var CALL_NON_FUNCTION; var CALL_NON_FUNCTION_AS_CONSTRUCTOR; @@ -482,6 +483,21 @@ SHR_STRONG = function SHR_STRONG(y) { ----------------------------- */ +// ECMA-262, section 11.8.7, page 54. +IN = function IN(x) { + if (!IS_SPEC_OBJECT(x)) { + throw %MakeTypeError(kInvalidInOperatorUse, this, x); + } + if (%_IsNonNegativeSmi(this)) { + if (IS_ARRAY(x) && %_HasFastPackedElements(x)) { + return this < x.length; + } + return %HasElement(x, this); + } + return %HasProperty(x, %$toName(this)); +} + + // ECMA-262, section 11.8.6, page 54. To make the implementation more // efficient, the return value should be zero if the 'this' is an // instance of F, and non-zero if not. This makes it possible to avoid diff --git a/src/runtime/runtime-numbers.cc b/src/runtime/runtime-numbers.cc index ae2633c23..7e6712ad2 100644 --- a/src/runtime/runtime-numbers.cc +++ b/src/runtime/runtime-numbers.cc @@ -548,6 +548,15 @@ RUNTIME_FUNCTION(Runtime_IsSmi) { } +RUNTIME_FUNCTION(Runtime_IsNonNegativeSmi) { + SealHandleScope shs(isolate); + DCHECK(args.length() == 1); + CONVERT_ARG_CHECKED(Object, obj, 0); + return isolate->heap()->ToBoolean(obj->IsSmi() && + Smi::cast(obj)->value() >= 0); +} + + RUNTIME_FUNCTION(Runtime_GetRootNaN) { SealHandleScope shs(isolate); DCHECK(args.length() == 0); diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index 59aac4800..064e4c216 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -779,36 +779,25 @@ RUNTIME_FUNCTION(Runtime_HasOwnProperty) { } -// ES6 section 12.9.3, operator in. RUNTIME_FUNCTION(Runtime_HasProperty) { HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_ARG_HANDLE_CHECKED(Object, key, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, object, 1); + DCHECK(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); - // Check that {object} is actually a receiver. - if (!object->IsJSReceiver()) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, - NewTypeError(MessageTemplate::kInvalidInOperatorUse, key, object)); - } - Handle receiver = Handle::cast(object); + Maybe maybe = JSReceiver::HasProperty(receiver, key); + if (!maybe.IsJust()) return isolate->heap()->exception(); + return isolate->heap()->ToBoolean(maybe.FromJust()); +} - // Check for fast element case. - uint32_t index = 0; - if (key->ToArrayIndex(&index)) { - Maybe maybe = JSReceiver::HasElement(receiver, index); - if (!maybe.IsJust()) return isolate->heap()->exception(); - return isolate->heap()->ToBoolean(maybe.FromJust()); - } - // Convert {key} to a Name first. - Handle name; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, - Runtime::ToName(isolate, key)); +RUNTIME_FUNCTION(Runtime_HasElement) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); + CONVERT_SMI_ARG_CHECKED(index, 1); - // Lookup property by {name} on {receiver}. - Maybe maybe = JSReceiver::HasProperty(receiver, name); + Maybe maybe = JSReceiver::HasElement(receiver, index); if (!maybe.IsJust()) return isolate->heap()->exception(); return isolate->heap()->ToBoolean(maybe.FromJust()); } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 3d822abf1..cb6f89e25 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -424,6 +424,7 @@ namespace internal { F(SmiLexicographicCompare, 2, 1) \ F(MaxSmi, 0, 1) \ F(IsSmi, 1, 1) \ + F(IsNonNegativeSmi, 1, 1) \ F(GetRootNaN, 0, 1) @@ -453,6 +454,7 @@ namespace internal { F(DeleteProperty_Strict, 2, 1) \ F(HasOwnProperty, 2, 1) \ F(HasProperty, 2, 1) \ + F(HasElement, 2, 1) \ F(IsPropertyEnumerable, 2, 1) \ F(GetPropertyNamesFast, 1, 1) \ F(GetOwnPropertyNames, 2, 1) \ diff --git a/test/cctest/compiler/test-run-inlining.cc b/test/cctest/compiler/test-run-inlining.cc index 5119bb73e..1b2559fc5 100644 --- a/test/cctest/compiler/test-run-inlining.cc +++ b/test/cctest/compiler/test-run-inlining.cc @@ -415,6 +415,20 @@ TEST(InlineIntrinsicIsSmi) { } +TEST(InlineIntrinsicIsNonNegativeSmi) { + FunctionTester T( + "(function () {" + " var x = 42;" + " function bar(s,t) { return %_IsNonNegativeSmi(x); };" + " return bar;" + "})();", + kInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.true_value(), T.Val(12), T.Val(4)); +} + + TEST(InlineIntrinsicIsArray) { FunctionTester T( "(function () {" diff --git a/test/cctest/compiler/test-run-intrinsics.cc b/test/cctest/compiler/test-run-intrinsics.cc index ce449075c..1fa37748c 100644 --- a/test/cctest/compiler/test-run-intrinsics.cc +++ b/test/cctest/compiler/test-run-intrinsics.cc @@ -128,6 +128,18 @@ TEST(IsMinusZero) { } +TEST(IsNonNegativeSmi) { + 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) { FunctionTester T("(function(a) { return %_IsObject(a); })", flags); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 5b8417f77..dad5d6caf 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -19298,7 +19298,8 @@ TEST(AccessCheckThrows) { CheckCorrectThrow("%DeleteProperty_Sloppy(other, '1')"); CheckCorrectThrow("%DeleteProperty_Strict(other, '1')"); CheckCorrectThrow("%HasOwnProperty(other, 'x')"); - CheckCorrectThrow("%HasProperty('x', other)"); + CheckCorrectThrow("%HasProperty(other, 'x')"); + CheckCorrectThrow("%HasElement(other, 1)"); CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); // PROPERTY_ATTRIBUTES_NONE = 0 CheckCorrectThrow("%DefineAccessorPropertyUnchecked(" diff --git a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc index 99f457496..92be4e43e 100644 --- a/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -125,6 +125,23 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsSmi) { } +// ----------------------------------------------------------------------------- +// %_IsNonNegativeSmi + + +TEST_F(JSIntrinsicLoweringTest, InlineIsNonNegativeSmi) { + 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::kInlineIsNonNegativeSmi, 1), input, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsObjectIsNonNegativeSmi(input)); +} + + // ----------------------------------------------------------------------------- // %_IsArray