[es2015] Fix ToPrimitive conversions in relational comparisons.
The order in which ToNumber(left) and ToPrimitive(right,hint Number) is called when performing an abstract relational comparison is observable, and we need to make sure to trigger the conversions in the correct order. Bug: chromium:687063 Change-Id: Idc9edb99643c4cf1774b89dcdc319ed5dc7cdc8a Reviewed-on: https://chromium-review.googlesource.com/1236557 Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#56125}
This commit is contained in:
parent
5e8581a77c
commit
08aec7d721
@ -10713,15 +10713,16 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
|
||||
}
|
||||
|
||||
// If {left} is a receiver, call ToPrimitive(left, hint Number).
|
||||
// Otherwise call ToNumeric(left) and then ToNumeric(right).
|
||||
// Otherwise call ToNumeric(right) and then ToNumeric(left), the
|
||||
// order here is important as it's observable by user code.
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
Label if_left_receiver(this, Label::kDeferred);
|
||||
GotoIf(IsJSReceiverInstanceType(left_instance_type),
|
||||
&if_left_receiver);
|
||||
|
||||
var_right.Bind(CallBuiltin(Builtins::kToNumeric, context, right));
|
||||
var_left.Bind(
|
||||
CallBuiltin(Builtins::kNonNumberToNumeric, context, left));
|
||||
var_right.Bind(CallBuiltin(Builtins::kToNumeric, context, right));
|
||||
Goto(&loop);
|
||||
|
||||
BIND(&if_left_receiver);
|
||||
|
31
test/mjsunit/regress/regress-crbug-687063.js
Normal file
31
test/mjsunit/regress/regress-crbug-687063.js
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
// Collect the actual properties looked up on the Proxy.
|
||||
const actual = [];
|
||||
|
||||
// Perform a relational comparison with a Proxy on the right hand
|
||||
// side and a Symbol which cannot be turned into a Number on the
|
||||
// left hand side.
|
||||
function foo() {
|
||||
actual.length = 0;
|
||||
const lhs = Symbol();
|
||||
const rhs = new Proxy({}, {
|
||||
get: function(target, property, receiver) {
|
||||
actual.push(property);
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
assertThrows(foo, TypeError);
|
||||
assertEquals([Symbol.toPrimitive, 'valueOf', 'toString'], actual);
|
||||
assertThrows(foo, TypeError);
|
||||
assertEquals([Symbol.toPrimitive, 'valueOf', 'toString'], actual);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertThrows(foo, TypeError);
|
||||
assertEquals([Symbol.toPrimitive, 'valueOf', 'toString'], actual);
|
Loading…
Reference in New Issue
Block a user