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}
This commit is contained in:
bmeurer 2015-08-13 06:06:45 -07:00 committed by Commit bot
parent 72d60a1e80
commit 96e331e2f2
23 changed files with 278 additions and 37 deletions

View File

@ -175,6 +175,7 @@ enum BuiltinExtraArguments {
V(SAR_STRONG, 1) \ V(SAR_STRONG, 1) \
V(SHR, 1) \ V(SHR, 1) \
V(SHR_STRONG, 1) \ V(SHR_STRONG, 1) \
V(IN, 1) \
V(INSTANCE_OF, 1) \ V(INSTANCE_OF, 1) \
V(CALL_NON_FUNCTION, 0) \ V(CALL_NON_FUNCTION, 0) \
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \ V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \

View File

@ -437,7 +437,7 @@ void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
void JSGenericLowering::LowerJSHasProperty(Node* node) { void JSGenericLowering::LowerJSHasProperty(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kHasProperty); ReplaceWithBuiltinCall(node, Builtins::IN, 2);
} }

View File

@ -52,6 +52,8 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE); return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
case Runtime::kInlineIsFunction: case Runtime::kInlineIsFunction:
return ReduceIsInstanceType(node, JS_FUNCTION_TYPE); return ReduceIsInstanceType(node, JS_FUNCTION_TYPE);
case Runtime::kInlineIsNonNegativeSmi:
return ReduceIsNonNegativeSmi(node);
case Runtime::kInlineIsRegExp: case Runtime::kInlineIsRegExp:
return ReduceIsInstanceType(node, JS_REGEXP_TYPE); return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
case Runtime::kInlineIsSmi: 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) { Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
return Change(node, simplified()->ObjectIsSmi()); return Change(node, simplified()->ObjectIsSmi());
} }

View File

@ -41,6 +41,7 @@ class JSIntrinsicLowering final : public AdvancedReducer {
Reduction ReduceIncrementStatsCounter(Node* node); Reduction ReduceIncrementStatsCounter(Node* node);
Reduction ReduceIsMinusZero(Node* node); Reduction ReduceIsMinusZero(Node* node);
Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type); Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type);
Reduction ReduceIsNonNegativeSmi(Node* node);
Reduction ReduceIsSmi(Node* node); Reduction ReduceIsSmi(Node* node);
Reduction ReduceJSValueGetValue(Node* node); Reduction ReduceJSValueGetValue(Node* node);
Reduction ReduceMapGetInstanceType(Node* node); Reduction ReduceMapGetInstanceType(Node* node);

View File

@ -1535,6 +1535,7 @@ Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
switch (CallRuntimeParametersOf(node->op()).id()) { switch (CallRuntimeParametersOf(node->op()).id()) {
case Runtime::kInlineIsSmi: case Runtime::kInlineIsSmi:
case Runtime::kInlineIsNonNegativeSmi:
case Runtime::kInlineIsArray: case Runtime::kInlineIsArray:
case Runtime::kInlineIsDate: case Runtime::kInlineIsDate:
case Runtime::kInlineIsTypedArray: case Runtime::kInlineIsTypedArray:

View File

@ -3350,6 +3350,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -5065,7 +5086,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ LoadRoot(ip, Heap::kTrueValueRootIndex); __ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r0, ip); __ cmp(r0, ip);

View File

@ -3043,6 +3043,28 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -4769,7 +4791,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ CompareRoot(x0, Heap::kTrueValueRootIndex); __ CompareRoot(x0, Heap::kTrueValueRootIndex);
Split(eq, if_true, if_false, fall_through); Split(eq, if_true, if_false, fall_through);

View File

@ -488,6 +488,7 @@ class FullCodeGenerator: public AstVisitor {
#define FOR_EACH_FULL_CODE_INTRINSIC(F) \ #define FOR_EACH_FULL_CODE_INTRINSIC(F) \
F(IsSmi) \ F(IsSmi) \
F(IsNonNegativeSmi) \
F(IsArray) \ F(IsArray) \
F(IsTypedArray) \ F(IsTypedArray) \
F(IsRegExp) \ F(IsRegExp) \

View File

@ -3243,6 +3243,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -5004,7 +5025,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ cmp(eax, isolate()->factory()->true_value()); __ cmp(eax, isolate()->factory()->true_value());
Split(equal, if_true, if_false, fall_through); Split(equal, if_true, if_false, fall_through);

View File

@ -3341,6 +3341,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -5090,7 +5111,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ LoadRoot(t0, Heap::kTrueValueRootIndex); __ LoadRoot(t0, Heap::kTrueValueRootIndex);
Split(eq, v0, Operand(t0), if_true, if_false, fall_through); Split(eq, v0, Operand(t0), if_true, if_false, fall_through);

View File

@ -3342,6 +3342,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -5092,7 +5113,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ LoadRoot(a4, Heap::kTrueValueRootIndex); __ LoadRoot(a4, Heap::kTrueValueRootIndex);
Split(eq, v0, Operand(a4), if_true, if_false, fall_through); Split(eq, v0, Operand(a4), if_true, if_false, fall_through);

View File

@ -3342,6 +3342,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -5111,7 +5132,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ LoadRoot(ip, Heap::kTrueValueRootIndex); __ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r3, ip); __ cmp(r3, ip);

View File

@ -3235,6 +3235,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -5013,7 +5034,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ CompareRoot(rax, Heap::kTrueValueRootIndex); __ CompareRoot(rax, Heap::kTrueValueRootIndex);
Split(equal, if_true, if_false, fall_through); Split(equal, if_true, if_false, fall_through);

View File

@ -3234,6 +3234,27 @@ void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
} }
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
ZoneList<Expression*>* 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) { void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1); DCHECK(args->length() == 1);
@ -5021,7 +5042,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
switch (op) { switch (op) {
case Token::IN: case Token::IN:
VisitForStackValue(expr->right()); VisitForStackValue(expr->right());
__ CallRuntime(Runtime::kHasProperty, 2); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
__ cmp(eax, isolate()->factory()->true_value()); __ cmp(eax, isolate()->factory()->true_value());
Split(equal, if_true, if_false, fall_through); Split(equal, if_true, if_false, fall_through);

View File

@ -11360,10 +11360,11 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
return ast_context()->ReturnInstruction(result, expr->id()); return ast_context()->ReturnInstruction(result, expr->id());
} else if (op == Token::IN) { } else if (op == Token::IN) {
HValue* function = AddLoadJSBuiltin(Builtins::IN);
Add<HPushArguments>(left, right); Add<HPushArguments>(left, right);
HInstruction* result = // TODO(olivf) InvokeFunction produces a check for the parameter count,
New<HCallRuntime>(isolate()->factory()->empty_string(), // even though we are certain to pass the correct number of arguments here.
Runtime::FunctionForId(Runtime::kHasProperty), 2); HInstruction* result = New<HInvokeFunction>(function, 2);
return ast_context()->ReturnInstruction(result, expr->id()); return ast_context()->ReturnInstruction(result, expr->id());
} }

View File

@ -44,6 +44,7 @@ var SAR;
var SAR_STRONG; var SAR_STRONG;
var SHR; var SHR;
var SHR_STRONG; var SHR_STRONG;
var IN;
var INSTANCE_OF; var INSTANCE_OF;
var CALL_NON_FUNCTION; var CALL_NON_FUNCTION;
var CALL_NON_FUNCTION_AS_CONSTRUCTOR; 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 // 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 // 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 // instance of F, and non-zero if not. This makes it possible to avoid

View File

@ -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) { RUNTIME_FUNCTION(Runtime_GetRootNaN) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK(args.length() == 0); DCHECK(args.length() == 0);

View File

@ -779,36 +779,25 @@ RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
} }
// ES6 section 12.9.3, operator in.
RUNTIME_FUNCTION(Runtime_HasProperty) { RUNTIME_FUNCTION(Runtime_HasProperty) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Object, key, 0); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 1); CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
// Check that {object} is actually a receiver. Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
if (!object->IsJSReceiver()) { if (!maybe.IsJust()) return isolate->heap()->exception();
THROW_NEW_ERROR_RETURN_FAILURE( return isolate->heap()->ToBoolean(maybe.FromJust());
isolate, }
NewTypeError(MessageTemplate::kInvalidInOperatorUse, key, object));
}
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
// Check for fast element case.
uint32_t index = 0;
if (key->ToArrayIndex(&index)) {
Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
if (!maybe.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(maybe.FromJust());
}
// Convert {key} to a Name first. RUNTIME_FUNCTION(Runtime_HasElement) {
Handle<Name> name; HandleScope scope(isolate);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, DCHECK(args.length() == 2);
Runtime::ToName(isolate, key)); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
// Lookup property by {name} on {receiver}. Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
Maybe<bool> maybe = JSReceiver::HasProperty(receiver, name);
if (!maybe.IsJust()) return isolate->heap()->exception(); if (!maybe.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(maybe.FromJust()); return isolate->heap()->ToBoolean(maybe.FromJust());
} }

View File

@ -424,6 +424,7 @@ namespace internal {
F(SmiLexicographicCompare, 2, 1) \ F(SmiLexicographicCompare, 2, 1) \
F(MaxSmi, 0, 1) \ F(MaxSmi, 0, 1) \
F(IsSmi, 1, 1) \ F(IsSmi, 1, 1) \
F(IsNonNegativeSmi, 1, 1) \
F(GetRootNaN, 0, 1) F(GetRootNaN, 0, 1)
@ -453,6 +454,7 @@ namespace internal {
F(DeleteProperty_Strict, 2, 1) \ F(DeleteProperty_Strict, 2, 1) \
F(HasOwnProperty, 2, 1) \ F(HasOwnProperty, 2, 1) \
F(HasProperty, 2, 1) \ F(HasProperty, 2, 1) \
F(HasElement, 2, 1) \
F(IsPropertyEnumerable, 2, 1) \ F(IsPropertyEnumerable, 2, 1) \
F(GetPropertyNamesFast, 1, 1) \ F(GetPropertyNamesFast, 1, 1) \
F(GetOwnPropertyNames, 2, 1) \ F(GetOwnPropertyNames, 2, 1) \

View File

@ -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) { TEST(InlineIntrinsicIsArray) {
FunctionTester T( FunctionTester T(
"(function () {" "(function () {"

View File

@ -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) { TEST(IsObject) {
FunctionTester T("(function(a) { return %_IsObject(a); })", flags); FunctionTester T("(function(a) { return %_IsObject(a); })", flags);

View File

@ -19298,7 +19298,8 @@ TEST(AccessCheckThrows) {
CheckCorrectThrow("%DeleteProperty_Sloppy(other, '1')"); CheckCorrectThrow("%DeleteProperty_Sloppy(other, '1')");
CheckCorrectThrow("%DeleteProperty_Strict(other, '1')"); CheckCorrectThrow("%DeleteProperty_Strict(other, '1')");
CheckCorrectThrow("%HasOwnProperty(other, 'x')"); CheckCorrectThrow("%HasOwnProperty(other, 'x')");
CheckCorrectThrow("%HasProperty('x', other)"); CheckCorrectThrow("%HasProperty(other, 'x')");
CheckCorrectThrow("%HasElement(other, 1)");
CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
// PROPERTY_ATTRIBUTES_NONE = 0 // PROPERTY_ATTRIBUTES_NONE = 0
CheckCorrectThrow("%DefineAccessorPropertyUnchecked(" CheckCorrectThrow("%DefineAccessorPropertyUnchecked("

View File

@ -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 // %_IsArray