Commit d00da47b authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Don't use the CompareIC in JSGenericLowering.

The CompareICStub produces an untagged raw word value, which has to be
translated to true or false manually in the TurboFan code. But for lazy
bailout after the CompareIC, we immediately go back to fullcodegen or
Ignition with the raw value, to a location where both fullcodegen and
Ignition expect a boolean value, which might crash or in the worst case
(depending on the exact computation inside the CompareIC) could lead to
arbitrary memory access.

Short-term fix is to use the proper runtime functions (unified with the
interpreter now) for comparisons. Next task is to provide optimized
versions of these based on the CodeStubAssembler, which can then be used
via code stubs in TurboFan or directly in handlers in the interpreter.

R=mstarzinger@chromium.org
BUG=v8:4788
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#34335}
parent 81f12a74
...@@ -675,7 +675,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { ...@@ -675,7 +675,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(lhs, rhs); __ Push(lhs, rhs);
__ CallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); __ CallRuntime(strict() ? Runtime::kStrictEqual : Runtime::kEqual);
} }
// Turn true into 0 and false into some non-zero value. // Turn true into 0 and false into some non-zero value.
STATIC_ASSERT(EQUAL == 0); STATIC_ASSERT(EQUAL == 0);
......
...@@ -632,7 +632,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { ...@@ -632,7 +632,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(lhs, rhs); __ Push(lhs, rhs);
__ CallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); __ CallRuntime(strict() ? Runtime::kStrictEqual : Runtime::kEqual);
} }
// Turn true into 0 and false into some non-zero value. // Turn true into 0 and false into some non-zero value.
STATIC_ASSERT(EQUAL == 0); STATIC_ASSERT(EQUAL == 0);
......
...@@ -83,117 +83,22 @@ REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV) ...@@ -83,117 +83,22 @@ REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV)
REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD) REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
#undef REPLACE_BINARY_OP_IC_CALL #undef REPLACE_BINARY_OP_IC_CALL
// These ops are not language mode dependent; we arbitrarily pass Strength::WEAK
// here.
#define REPLACE_COMPARE_IC_CALL(op, token) \
void JSGenericLowering::Lower##op(Node* node) { \
ReplaceWithCompareIC(node, token); \
}
REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ)
REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE)
REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT)
REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT)
REPLACE_COMPARE_IC_CALL(JSLessThan, Token::LT)
REPLACE_COMPARE_IC_CALL(JSGreaterThan, Token::GT)
REPLACE_COMPARE_IC_CALL(JSLessThanOrEqual, Token::LTE)
REPLACE_COMPARE_IC_CALL(JSGreaterThanOrEqual, Token::GTE)
#undef REPLACE_COMPARE_IC_CALL
#define REPLACE_RUNTIME_CALL(op, fun) \ #define REPLACE_RUNTIME_CALL(op, fun) \
void JSGenericLowering::Lower##op(Node* node) { \ void JSGenericLowering::Lower##op(Node* node) { \
ReplaceWithRuntimeCall(node, fun); \ ReplaceWithRuntimeCall(node, fun); \
} }
REPLACE_RUNTIME_CALL(JSEqual, Runtime::kEqual)
REPLACE_RUNTIME_CALL(JSNotEqual, Runtime::kNotEqual)
REPLACE_RUNTIME_CALL(JSStrictEqual, Runtime::kStrictEqual)
REPLACE_RUNTIME_CALL(JSStrictNotEqual, Runtime::kStrictNotEqual)
REPLACE_RUNTIME_CALL(JSLessThan, Runtime::kLessThan)
REPLACE_RUNTIME_CALL(JSGreaterThan, Runtime::kGreaterThan)
REPLACE_RUNTIME_CALL(JSLessThanOrEqual, Runtime::kLessThanOrEqual)
REPLACE_RUNTIME_CALL(JSGreaterThanOrEqual, Runtime::kGreaterThanOrEqual)
REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext) REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext) REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver) REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
#undef REPLACE_RUNTIME #undef REPLACE_RUNTIME_CALL
static CallDescriptor::Flags FlagsForNode(Node* node) {
CallDescriptor::Flags result = CallDescriptor::kNoFlags;
if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
result |= CallDescriptor::kNeedsFrameState;
}
return result;
}
void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
Callable callable = CodeFactory::CompareIC(isolate(), token);
// Create a new call node asking a CompareIC for help.
NodeVector inputs(zone());
inputs.reserve(node->InputCount() + 1);
inputs.push_back(jsgraph()->HeapConstant(callable.code()));
inputs.push_back(NodeProperties::GetValueInput(node, 0));
inputs.push_back(NodeProperties::GetValueInput(node, 1));
inputs.push_back(NodeProperties::GetContextInput(node));
// Some comparisons (StrictEqual) don't have an effect, control or frame
// state inputs, so handle those cases here.
if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
inputs.push_back(NodeProperties::GetFrameStateInput(node, 0));
}
Node* effect = (node->op()->EffectInputCount() > 0)
? NodeProperties::GetEffectInput(node)
: graph()->start();
inputs.push_back(effect);
Node* control = (node->op()->ControlInputCount() > 0)
? NodeProperties::GetControlInput(node)
: graph()->start();
inputs.push_back(control);
CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor(
isolate(), zone(), callable.descriptor(), 0,
CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node),
Operator::kNoProperties, MachineType::IntPtr());
Node* compare =
graph()->NewNode(common()->Call(desc_compare),
static_cast<int>(inputs.size()), &inputs.front());
// Decide how the return value from the above CompareIC can be converted into
// a JavaScript boolean oddball depending on the given token.
Node* false_value = jsgraph()->FalseConstant();
Node* true_value = jsgraph()->TrueConstant();
const Operator* op = nullptr;
switch (token) {
case Token::EQ: // a == 0
case Token::EQ_STRICT:
op = machine()->WordEqual();
break;
case Token::NE: // a != 0 becomes !(a == 0)
case Token::NE_STRICT:
op = machine()->WordEqual();
std::swap(true_value, false_value);
break;
case Token::LT: // a < 0
op = machine()->IntLessThan();
break;
case Token::GT: // a > 0 becomes !(a <= 0)
op = machine()->IntLessThanOrEqual();
std::swap(true_value, false_value);
break;
case Token::LTE: // a <= 0
op = machine()->IntLessThanOrEqual();
break;
case Token::GTE: // a >= 0 becomes !(a < 0)
op = machine()->IntLessThan();
std::swap(true_value, false_value);
break;
default:
UNREACHABLE();
}
Node* booleanize = graph()->NewNode(op, compare, jsgraph()->ZeroConstant());
// Finally patch the original node to select a boolean.
NodeProperties::ReplaceUses(node, node, compare, compare, compare);
node->TrimInputCount(3);
node->ReplaceInput(0, booleanize);
node->ReplaceInput(1, true_value);
node->ReplaceInput(2, false_value);
NodeProperties::ChangeOp(node,
common()->Select(MachineRepresentation::kTagged));
}
void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable, void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
CallDescriptor::Flags flags) { CallDescriptor::Flags flags) {
...@@ -209,11 +114,12 @@ void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable, ...@@ -209,11 +114,12 @@ void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
void JSGenericLowering::ReplaceWithRuntimeCall(Node* node, void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
Runtime::FunctionId f, Runtime::FunctionId f,
int nargs_override) { int nargs_override) {
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
Operator::Properties properties = node->op()->properties(); Operator::Properties properties = node->op()->properties();
const Runtime::Function* fun = Runtime::FunctionForId(f); const Runtime::Function* fun = Runtime::FunctionForId(f);
int nargs = (nargs_override < 0) ? fun->nargs : nargs_override; int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( CallDescriptor* desc =
zone(), f, nargs, properties, CallDescriptor::kNeedsFrameState); Linkage::GetRuntimeCallDescriptor(zone(), f, nargs, properties, flags);
Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate())); Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate()));
Node* arity = jsgraph()->Int32Constant(nargs); Node* arity = jsgraph()->Int32Constant(nargs);
node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size)); node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
......
...@@ -36,7 +36,6 @@ class JSGenericLowering final : public Reducer { ...@@ -36,7 +36,6 @@ class JSGenericLowering final : public Reducer {
#undef DECLARE_LOWER #undef DECLARE_LOWER
// Helpers to replace existing nodes with a generic call. // Helpers to replace existing nodes with a generic call.
void ReplaceWithCompareIC(Node* node, Token::Value token);
void ReplaceWithStubCall(Node* node, Callable c, CallDescriptor::Flags flags); void ReplaceWithStubCall(Node* node, Callable c, CallDescriptor::Flags flags);
void ReplaceWithRuntimeCall(Node* node, Runtime::FunctionId f, int args = -1); void ReplaceWithRuntimeCall(Node* node, Runtime::FunctionId f, int args = -1);
......
...@@ -1447,7 +1447,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { ...@@ -1447,7 +1447,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(edx); __ Push(edx);
__ Push(eax); __ Push(eax);
__ CallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); __ CallRuntime(strict() ? Runtime::kStrictEqual : Runtime::kEqual);
} }
// Turn true into 0 and false into some non-zero value. // Turn true into 0 and false into some non-zero value.
STATIC_ASSERT(EQUAL == 0); STATIC_ASSERT(EQUAL == 0);
......
...@@ -1144,7 +1144,7 @@ void Interpreter::DoNewWide(InterpreterAssembler* assembler) { ...@@ -1144,7 +1144,7 @@ void Interpreter::DoNewWide(InterpreterAssembler* assembler) {
// //
// Test if the value in the <src> register equals the accumulator. // Test if the value in the <src> register equals the accumulator.
void Interpreter::DoTestEqual(InterpreterAssembler* assembler) { void Interpreter::DoTestEqual(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kEquals, assembler); DoBinaryOp(Runtime::kEqual, assembler);
} }
...@@ -1152,7 +1152,7 @@ void Interpreter::DoTestEqual(InterpreterAssembler* assembler) { ...@@ -1152,7 +1152,7 @@ void Interpreter::DoTestEqual(InterpreterAssembler* assembler) {
// //
// Test if the value in the <src> register is not equal to the accumulator. // Test if the value in the <src> register is not equal to the accumulator.
void Interpreter::DoTestNotEqual(InterpreterAssembler* assembler) { void Interpreter::DoTestNotEqual(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kNotEquals, assembler); DoBinaryOp(Runtime::kNotEqual, assembler);
} }
...@@ -1160,7 +1160,7 @@ void Interpreter::DoTestNotEqual(InterpreterAssembler* assembler) { ...@@ -1160,7 +1160,7 @@ void Interpreter::DoTestNotEqual(InterpreterAssembler* assembler) {
// //
// Test if the value in the <src> register is strictly equal to the accumulator. // Test if the value in the <src> register is strictly equal to the accumulator.
void Interpreter::DoTestEqualStrict(InterpreterAssembler* assembler) { void Interpreter::DoTestEqualStrict(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kStrictEquals, assembler); DoBinaryOp(Runtime::kStrictEqual, assembler);
} }
...@@ -1169,7 +1169,7 @@ void Interpreter::DoTestEqualStrict(InterpreterAssembler* assembler) { ...@@ -1169,7 +1169,7 @@ void Interpreter::DoTestEqualStrict(InterpreterAssembler* assembler) {
// Test if the value in the <src> register is not strictly equal to the // Test if the value in the <src> register is not strictly equal to the
// accumulator. // accumulator.
void Interpreter::DoTestNotEqualStrict(InterpreterAssembler* assembler) { void Interpreter::DoTestNotEqualStrict(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kStrictNotEquals, assembler); DoBinaryOp(Runtime::kStrictNotEqual, assembler);
} }
...@@ -1177,7 +1177,7 @@ void Interpreter::DoTestNotEqualStrict(InterpreterAssembler* assembler) { ...@@ -1177,7 +1177,7 @@ void Interpreter::DoTestNotEqualStrict(InterpreterAssembler* assembler) {
// //
// Test if the value in the <src> register is less than the accumulator. // Test if the value in the <src> register is less than the accumulator.
void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) { void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kInterpreterLessThan, assembler); DoBinaryOp(Runtime::kLessThan, assembler);
} }
...@@ -1185,7 +1185,7 @@ void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) { ...@@ -1185,7 +1185,7 @@ void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) {
// //
// Test if the value in the <src> register is greater than the accumulator. // Test if the value in the <src> register is greater than the accumulator.
void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) { void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kInterpreterGreaterThan, assembler); DoBinaryOp(Runtime::kGreaterThan, assembler);
} }
...@@ -1194,7 +1194,7 @@ void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) { ...@@ -1194,7 +1194,7 @@ void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) {
// Test if the value in the <src> register is less than or equal to the // Test if the value in the <src> register is less than or equal to the
// accumulator. // accumulator.
void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) { void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kInterpreterLessThanOrEqual, assembler); DoBinaryOp(Runtime::kLessThanOrEqual, assembler);
} }
...@@ -1203,7 +1203,7 @@ void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) { ...@@ -1203,7 +1203,7 @@ void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) {
// Test if the value in the <src> register is greater than or equal to the // Test if the value in the <src> register is greater than or equal to the
// accumulator. // accumulator.
void Interpreter::DoTestGreaterThanOrEqual(InterpreterAssembler* assembler) { void Interpreter::DoTestGreaterThanOrEqual(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kInterpreterGreaterThanOrEqual, assembler); DoBinaryOp(Runtime::kGreaterThanOrEqual, assembler);
} }
......
...@@ -722,7 +722,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { ...@@ -722,7 +722,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(lhs, rhs); __ Push(lhs, rhs);
__ CallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); __ CallRuntime(strict() ? Runtime::kStrictEqual : Runtime::kEqual);
} }
// Turn true into 0 and false into some non-zero value. // Turn true into 0 and false into some non-zero value.
STATIC_ASSERT(EQUAL == 0); STATIC_ASSERT(EQUAL == 0);
......
...@@ -719,7 +719,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { ...@@ -719,7 +719,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(lhs, rhs); __ Push(lhs, rhs);
__ CallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); __ CallRuntime(strict() ? Runtime::kStrictEqual : Runtime::kEqual);
} }
// Turn true into 0 and false into some non-zero value. // Turn true into 0 and false into some non-zero value.
STATIC_ASSERT(EQUAL == 0); STATIC_ASSERT(EQUAL == 0);
......
...@@ -1353,6 +1353,10 @@ int HeapNumber::get_sign() { ...@@ -1353,6 +1353,10 @@ int HeapNumber::get_sign() {
bool Simd128Value::Equals(Simd128Value* that) { bool Simd128Value::Equals(Simd128Value* that) {
// TODO(bmeurer): This doesn't match the SIMD.js specification, but it seems
// to be consistent with what the CompareICStub does, and what is tested in
// the current SIMD.js testsuite.
if (this == that) return true;
#define SIMD128_VALUE(TYPE, Type, type, lane_count, lane_type) \ #define SIMD128_VALUE(TYPE, Type, type, lane_count, lane_type) \
if (this->Is##Type()) { \ if (this->Is##Type()) { \
if (!that->Is##Type()) return false; \ if (!that->Is##Type()) return false; \
......
...@@ -16,62 +16,6 @@ ...@@ -16,62 +16,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
RUNTIME_FUNCTION(Runtime_InterpreterLessThan) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::LessThan(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterGreaterThan) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::GreaterThan(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterLessThanOrEqual) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::LessThanOrEqual(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterGreaterThanOrEqual) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::GreaterThanOrEqual(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterToBoolean) { RUNTIME_FUNCTION(Runtime_InterpreterToBoolean) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
......
...@@ -140,7 +140,7 @@ RUNTIME_FUNCTION(Runtime_BitwiseXor) { ...@@ -140,7 +140,7 @@ RUNTIME_FUNCTION(Runtime_BitwiseXor) {
return *result; return *result;
} }
RUNTIME_FUNCTION(Runtime_Equals) { RUNTIME_FUNCTION(Runtime_Equal) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0); CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
...@@ -150,7 +150,7 @@ RUNTIME_FUNCTION(Runtime_Equals) { ...@@ -150,7 +150,7 @@ RUNTIME_FUNCTION(Runtime_Equals) {
return isolate->heap()->ToBoolean(result.FromJust()); return isolate->heap()->ToBoolean(result.FromJust());
} }
RUNTIME_FUNCTION(Runtime_NotEquals) { RUNTIME_FUNCTION(Runtime_NotEqual) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0); CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
...@@ -160,7 +160,7 @@ RUNTIME_FUNCTION(Runtime_NotEquals) { ...@@ -160,7 +160,7 @@ RUNTIME_FUNCTION(Runtime_NotEquals) {
return isolate->heap()->ToBoolean(!result.FromJust()); return isolate->heap()->ToBoolean(!result.FromJust());
} }
RUNTIME_FUNCTION(Runtime_StrictEquals) { RUNTIME_FUNCTION(Runtime_StrictEqual) {
SealHandleScope scope(isolate); SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(Object, x, 0); CONVERT_ARG_CHECKED(Object, x, 0);
...@@ -168,7 +168,7 @@ RUNTIME_FUNCTION(Runtime_StrictEquals) { ...@@ -168,7 +168,7 @@ RUNTIME_FUNCTION(Runtime_StrictEquals) {
return isolate->heap()->ToBoolean(x->StrictEquals(y)); return isolate->heap()->ToBoolean(x->StrictEquals(y));
} }
RUNTIME_FUNCTION(Runtime_StrictNotEquals) { RUNTIME_FUNCTION(Runtime_StrictNotEqual) {
SealHandleScope scope(isolate); SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(Object, x, 0); CONVERT_ARG_CHECKED(Object, x, 0);
...@@ -176,5 +176,45 @@ RUNTIME_FUNCTION(Runtime_StrictNotEquals) { ...@@ -176,5 +176,45 @@ RUNTIME_FUNCTION(Runtime_StrictNotEquals) {
return isolate->heap()->ToBoolean(!x->StrictEquals(y)); return isolate->heap()->ToBoolean(!x->StrictEquals(y));
} }
RUNTIME_FUNCTION(Runtime_LessThan) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::LessThan(x, y);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
}
RUNTIME_FUNCTION(Runtime_GreaterThan) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::GreaterThan(x, y);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
}
RUNTIME_FUNCTION(Runtime_LessThanOrEqual) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::LessThanOrEqual(x, y);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
}
RUNTIME_FUNCTION(Runtime_GreaterThanOrEqual) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::GreaterThanOrEqual(x, y);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -206,10 +206,6 @@ namespace internal { ...@@ -206,10 +206,6 @@ namespace internal {
F(ForInStep, 1, 1) F(ForInStep, 1, 1)
#define FOR_EACH_INTRINSIC_INTERPRETER(F) \ #define FOR_EACH_INTRINSIC_INTERPRETER(F) \
F(InterpreterLessThan, 2, 1) \
F(InterpreterGreaterThan, 2, 1) \
F(InterpreterLessThanOrEqual, 2, 1) \
F(InterpreterGreaterThanOrEqual, 2, 1) \
F(InterpreterToBoolean, 1, 1) \ F(InterpreterToBoolean, 1, 1) \
F(InterpreterLogicalNot, 1, 1) \ F(InterpreterLogicalNot, 1, 1) \
F(InterpreterNewClosure, 2, 1) \ F(InterpreterNewClosure, 2, 1) \
...@@ -484,10 +480,14 @@ namespace internal { ...@@ -484,10 +480,14 @@ namespace internal {
F(BitwiseAnd, 2, 1) \ F(BitwiseAnd, 2, 1) \
F(BitwiseOr, 2, 1) \ F(BitwiseOr, 2, 1) \
F(BitwiseXor, 2, 1) \ F(BitwiseXor, 2, 1) \
F(Equals, 2, 1) \ F(Equal, 2, 1) \
F(NotEquals, 2, 1) \ F(NotEqual, 2, 1) \
F(StrictEquals, 2, 1) \ F(StrictEqual, 2, 1) \
F(StrictNotEquals, 2, 1) F(StrictNotEqual, 2, 1) \
F(LessThan, 2, 1) \
F(GreaterThan, 2, 1) \
F(LessThanOrEqual, 2, 1) \
F(GreaterThanOrEqual, 2, 1)
#define FOR_EACH_INTRINSIC_PROXY(F) \ #define FOR_EACH_INTRINSIC_PROXY(F) \
F(IsJSProxy, 1, 1) \ F(IsJSProxy, 1, 1) \
......
...@@ -1325,7 +1325,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { ...@@ -1325,7 +1325,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(rdx); __ Push(rdx);
__ Push(rax); __ Push(rax);
__ CallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); __ CallRuntime(strict() ? Runtime::kStrictEqual : Runtime::kEqual);
} }
// Turn true into 0 and false into some non-zero value. // Turn true into 0 and false into some non-zero value.
STATIC_ASSERT(EQUAL == 0); STATIC_ASSERT(EQUAL == 0);
......
...@@ -865,7 +865,6 @@ ...@@ -865,7 +865,6 @@
# TODO(rmcilroy,4680): Test assert failures. # TODO(rmcilroy,4680): Test assert failures.
'array-literal-feedback': [FAIL], 'array-literal-feedback': [FAIL],
'debug-liveedit-2': [FAIL], 'debug-liveedit-2': [FAIL],
'compiler/deopt-tonumber-compare': [FAIL],
'es6/mirror-collections': [FAIL], 'es6/mirror-collections': [FAIL],
'es6/regress/regress-468661': [FAIL], 'es6/regress/regress-468661': [FAIL],
'regress/regress-2618': [FAIL], 'regress/regress-2618': [FAIL],
......
// Copyright 2016 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
var f = (function() {
"use asm";
function foo(x) {
return x == 0;
}
return foo;
})();
function deopt(f) {
return {
toString : function() {
%DeoptimizeFunction(f);
return "2";
}
};
}
%OptimizeFunctionOnNextCall(f);
assertFalse(f(deopt(f)));
// Copyright 2016 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
var f = (function() {
"use asm";
function foo(x) {
return x < x;
}
return foo;
})();
function deopt(f) {
return {
toString : function() {
%DeoptimizeFunction(f);
return "2";
}
};
}
%OptimizeFunctionOnNextCall(f);
assertFalse(f(deopt(f)));
...@@ -23,12 +23,6 @@ class RuntimeInterpreterTest : public TestWithIsolateAndZone { ...@@ -23,12 +23,6 @@ class RuntimeInterpreterTest : public TestWithIsolateAndZone {
bool TestOperatorWithObjects(RuntimeMethod method, Handle<Object> lhs, bool TestOperatorWithObjects(RuntimeMethod method, Handle<Object> lhs,
Handle<Object> rhs, bool expected); Handle<Object> rhs, bool expected);
bool TestOperator(RuntimeMethod method, int32_t lhs, int32_t rhs,
bool expected);
bool TestOperator(RuntimeMethod method, double lhs, double rhs,
bool expected);
bool TestOperator(RuntimeMethod method, const char* lhs, const char* rhs,
bool expected);
}; };
...@@ -44,87 +38,6 @@ bool RuntimeInterpreterTest::TestOperatorWithObjects(RuntimeMethod method, ...@@ -44,87 +38,6 @@ bool RuntimeInterpreterTest::TestOperatorWithObjects(RuntimeMethod method,
} }
bool RuntimeInterpreterTest::TestOperator(RuntimeMethod method, int32_t lhs,
int32_t rhs, bool expected) {
Handle<Object> x = isolate()->factory()->NewNumberFromInt(lhs);
Handle<Object> y = isolate()->factory()->NewNumberFromInt(rhs);
return TestOperatorWithObjects(method, x, y, expected);
}
bool RuntimeInterpreterTest::TestOperator(RuntimeMethod method, double lhs,
double rhs, bool expected) {
Handle<Object> x = isolate()->factory()->NewNumber(lhs);
Handle<Object> y = isolate()->factory()->NewNumber(rhs);
CHECK_EQ(HeapNumber::cast(*x)->value(), lhs);
CHECK_EQ(HeapNumber::cast(*y)->value(), rhs);
return TestOperatorWithObjects(method, x, y, expected);
}
bool RuntimeInterpreterTest::TestOperator(RuntimeMethod method, const char* lhs,
const char* rhs, bool expected) {
Handle<Object> x = isolate()->factory()->NewStringFromAsciiChecked(lhs);
Handle<Object> y = isolate()->factory()->NewStringFromAsciiChecked(rhs);
return TestOperatorWithObjects(method, x, y, expected);
}
TEST_F(RuntimeInterpreterTest, TestOperatorsWithIntegers) {
int32_t inputs[] = {kMinInt, Smi::kMinValue, -17, -1, 0, 1,
991, Smi::kMaxValue, kMaxInt};
TRACED_FOREACH(int, lhs, inputs) {
TRACED_FOREACH(int, rhs, inputs) {
#define INTEGER_OPERATOR_CHECK(r, op, x, y) \
CHECK(TestOperator(Runtime_Interpreter##r, x, y, x op y))
INTEGER_OPERATOR_CHECK(LessThan, <, lhs, rhs);
INTEGER_OPERATOR_CHECK(GreaterThan, >, lhs, rhs);
INTEGER_OPERATOR_CHECK(LessThanOrEqual, <=, lhs, rhs);
INTEGER_OPERATOR_CHECK(GreaterThanOrEqual, >=, lhs, rhs);
#undef INTEGER_OPERATOR_CHECK
}
}
}
TEST_F(RuntimeInterpreterTest, TestOperatorsWithDoubles) {
double inputs[] = {std::numeric_limits<double>::min(),
std::numeric_limits<double>::max(),
-0.001,
0.01,
3.14,
-6.02214086e23};
TRACED_FOREACH(double, lhs, inputs) {
TRACED_FOREACH(double, rhs, inputs) {
#define DOUBLE_OPERATOR_CHECK(r, op, x, y) \
CHECK(TestOperator(Runtime_Interpreter##r, x, y, x op y))
DOUBLE_OPERATOR_CHECK(LessThan, <, lhs, rhs);
DOUBLE_OPERATOR_CHECK(GreaterThan, >, lhs, rhs);
DOUBLE_OPERATOR_CHECK(LessThanOrEqual, <=, lhs, rhs);
DOUBLE_OPERATOR_CHECK(GreaterThanOrEqual, >=, lhs, rhs);
#undef DOUBLE_OPERATOR_CHECK
}
}
}
TEST_F(RuntimeInterpreterTest, TestOperatorsWithString) {
const char* inputs[] = {"abc", "a", "def", "0"};
TRACED_FOREACH(const char*, lhs, inputs) {
TRACED_FOREACH(const char*, rhs, inputs) {
#define STRING_OPERATOR_CHECK(r, op, x, y) \
CHECK(TestOperator(Runtime_Interpreter##r, x, y, \
std::string(x) op std::string(y)))
STRING_OPERATOR_CHECK(LessThan, <, lhs, rhs);
STRING_OPERATOR_CHECK(GreaterThan, >, lhs, rhs);
STRING_OPERATOR_CHECK(LessThanOrEqual, <=, lhs, rhs);
STRING_OPERATOR_CHECK(GreaterThanOrEqual, >=, lhs, rhs);
#undef STRING_OPERATOR_CHECK
}
}
}
TEST_F(RuntimeInterpreterTest, ToBoolean) { TEST_F(RuntimeInterpreterTest, ToBoolean) {
double quiet_nan = std::numeric_limits<double>::quiet_NaN(); double quiet_nan = std::numeric_limits<double>::quiet_NaN();
std::pair<Handle<Object>, bool> cases[] = { std::pair<Handle<Object>, bool> cases[] = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment