2018-02-19 13:31:18 +00:00
|
|
|
// 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.
|
|
|
|
|
2018-02-21 11:38:35 +00:00
|
|
|
#include <cctype>
|
|
|
|
|
2018-07-06 11:05:49 +00:00
|
|
|
#include "src/compiler/compilation-dependencies.h"
|
2018-02-21 11:38:35 +00:00
|
|
|
#include "src/compiler/js-call-reducer.h"
|
2018-02-19 13:31:18 +00:00
|
|
|
#include "src/compiler/js-graph.h"
|
|
|
|
#include "src/compiler/simplified-operator.h"
|
2019-05-22 07:55:37 +00:00
|
|
|
#include "src/execution/isolate.h"
|
2018-04-09 19:11:22 +00:00
|
|
|
#include "src/heap/factory.h"
|
2019-05-23 08:51:46 +00:00
|
|
|
#include "src/objects/feedback-vector.h"
|
2018-02-19 13:31:18 +00:00
|
|
|
#include "test/unittests/compiler/graph-unittest.h"
|
2018-02-21 11:38:35 +00:00
|
|
|
#include "test/unittests/compiler/node-test-utils.h"
|
2018-02-19 13:31:18 +00:00
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
|
|
|
class JSCallReducerTest : public TypedGraphTest {
|
|
|
|
public:
|
|
|
|
JSCallReducerTest()
|
2019-02-27 18:10:29 +00:00
|
|
|
: TypedGraphTest(3), javascript_(zone()), deps_(broker(), zone()) {
|
2018-10-25 08:25:33 +00:00
|
|
|
broker()->SerializeStandardObjects();
|
2018-09-14 13:24:51 +00:00
|
|
|
}
|
2018-09-17 11:30:48 +00:00
|
|
|
~JSCallReducerTest() override = default;
|
2018-02-19 13:31:18 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
Reduction Reduce(Node* node) {
|
|
|
|
MachineOperatorBuilder machine(zone());
|
|
|
|
SimplifiedOperatorBuilder simplified(zone());
|
|
|
|
JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
|
|
|
|
&machine);
|
|
|
|
// TODO(titzer): mock the GraphReducer here for better unit testing.
|
|
|
|
GraphReducer graph_reducer(zone(), graph());
|
|
|
|
|
2018-10-12 09:18:57 +00:00
|
|
|
JSCallReducer reducer(&graph_reducer, &jsgraph, broker(),
|
2018-10-22 13:51:47 +00:00
|
|
|
JSCallReducer::kNoFlags, &deps_);
|
2018-02-19 13:31:18 +00:00
|
|
|
return reducer.Reduce(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSOperatorBuilder* javascript() { return &javascript_; }
|
|
|
|
|
2018-04-23 08:49:19 +00:00
|
|
|
Node* GlobalFunction(const char* name) {
|
|
|
|
Handle<JSFunction> f = Handle<JSFunction>::cast(
|
|
|
|
Object::GetProperty(
|
2018-07-17 08:49:20 +00:00
|
|
|
isolate(), isolate()->global_object(),
|
2018-04-23 08:49:19 +00:00
|
|
|
isolate()->factory()->NewStringFromAsciiChecked(name))
|
|
|
|
.ToHandleChecked());
|
|
|
|
return HeapConstant(f);
|
|
|
|
}
|
|
|
|
|
2018-02-21 11:38:35 +00:00
|
|
|
Node* MathFunction(const std::string& name) {
|
|
|
|
Handle<Object> m =
|
|
|
|
JSObject::GetProperty(
|
2018-06-19 09:00:37 +00:00
|
|
|
isolate(), isolate()->global_object(),
|
2018-02-21 11:38:35 +00:00
|
|
|
isolate()->factory()->NewStringFromAsciiChecked("Math"))
|
|
|
|
.ToHandleChecked();
|
|
|
|
Handle<JSFunction> f = Handle<JSFunction>::cast(
|
|
|
|
Object::GetProperty(
|
2018-07-17 08:49:20 +00:00
|
|
|
isolate(), m,
|
|
|
|
isolate()->factory()->NewStringFromAsciiChecked(name.c_str()))
|
2018-02-21 11:38:35 +00:00
|
|
|
.ToHandleChecked());
|
|
|
|
return HeapConstant(f);
|
|
|
|
}
|
|
|
|
|
2018-02-23 13:03:27 +00:00
|
|
|
Node* StringFunction(const char* name) {
|
|
|
|
Handle<Object> m =
|
|
|
|
JSObject::GetProperty(
|
2018-06-19 09:00:37 +00:00
|
|
|
isolate(), isolate()->global_object(),
|
2018-02-23 13:03:27 +00:00
|
|
|
isolate()->factory()->NewStringFromAsciiChecked("String"))
|
|
|
|
.ToHandleChecked();
|
|
|
|
Handle<JSFunction> f = Handle<JSFunction>::cast(
|
|
|
|
Object::GetProperty(
|
2018-07-17 08:49:20 +00:00
|
|
|
isolate(), m, isolate()->factory()->NewStringFromAsciiChecked(name))
|
2018-02-23 13:03:27 +00:00
|
|
|
.ToHandleChecked());
|
|
|
|
return HeapConstant(f);
|
|
|
|
}
|
|
|
|
|
2018-03-16 08:36:57 +00:00
|
|
|
Node* NumberFunction(const char* name) {
|
|
|
|
Handle<Object> m =
|
|
|
|
JSObject::GetProperty(
|
2018-06-19 09:00:37 +00:00
|
|
|
isolate(), isolate()->global_object(),
|
2018-03-16 08:36:57 +00:00
|
|
|
isolate()->factory()->NewStringFromAsciiChecked("Number"))
|
|
|
|
.ToHandleChecked();
|
|
|
|
Handle<JSFunction> f = Handle<JSFunction>::cast(
|
|
|
|
Object::GetProperty(
|
2018-07-17 08:49:20 +00:00
|
|
|
isolate(), m, isolate()->factory()->NewStringFromAsciiChecked(name))
|
2018-03-16 08:36:57 +00:00
|
|
|
.ToHandleChecked());
|
|
|
|
return HeapConstant(f);
|
|
|
|
}
|
|
|
|
|
2018-02-21 11:38:35 +00:00
|
|
|
std::string op_name_for(const char* fnc) {
|
|
|
|
std::string string_fnc(fnc);
|
|
|
|
char initial = std::toupper(fnc[0]);
|
|
|
|
return std::string("Number") + initial +
|
|
|
|
string_fnc.substr(1, std::string::npos);
|
|
|
|
}
|
|
|
|
|
2018-02-22 14:41:23 +00:00
|
|
|
const Operator* Call(int arity) {
|
|
|
|
FeedbackVectorSpec spec(zone());
|
|
|
|
spec.AddCallICSlot();
|
|
|
|
Handle<FeedbackMetadata> metadata = FeedbackMetadata::New(isolate(), &spec);
|
|
|
|
Handle<SharedFunctionInfo> shared =
|
2018-03-22 16:09:55 +00:00
|
|
|
isolate()->factory()->NewSharedFunctionInfoForBuiltin(
|
2018-03-23 14:24:03 +00:00
|
|
|
isolate()->factory()->empty_string(), Builtins::kIllegal);
|
2018-04-06 11:49:15 +00:00
|
|
|
// Set the raw feedback metadata to circumvent checks that we are not
|
|
|
|
// overwriting existing metadata.
|
|
|
|
shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
|
2019-03-25 15:05:47 +00:00
|
|
|
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
|
|
|
|
ClosureFeedbackCellArray::New(isolate(), shared);
|
2019-03-12 11:43:06 +00:00
|
|
|
Handle<FeedbackVector> vector =
|
|
|
|
FeedbackVector::New(isolate(), shared, closure_feedback_cell_array);
|
2018-09-10 08:44:50 +00:00
|
|
|
VectorSlotPair feedback(vector, FeedbackSlot(0), UNINITIALIZED);
|
2018-02-22 14:41:23 +00:00
|
|
|
return javascript()->Call(arity, CallFrequency(), feedback,
|
|
|
|
ConvertReceiverMode::kAny,
|
|
|
|
SpeculationMode::kAllowSpeculation);
|
|
|
|
}
|
|
|
|
|
2018-02-19 13:31:18 +00:00
|
|
|
private:
|
|
|
|
JSOperatorBuilder javascript_;
|
|
|
|
CompilationDependencies deps_;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, PromiseConstructorNoArgs) {
|
2018-06-26 10:14:12 +00:00
|
|
|
Node* promise =
|
|
|
|
HeapConstant(handle(native_context()->promise_function(), isolate()));
|
2018-02-19 13:31:18 +00:00
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
|
|
|
|
Node* construct =
|
|
|
|
graph()->NewNode(javascript()->Construct(2), promise, promise, context,
|
|
|
|
frame_state, effect, control);
|
|
|
|
|
|
|
|
Reduction r = Reduce(construct);
|
|
|
|
|
|
|
|
ASSERT_FALSE(r.Changed());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, PromiseConstructorSubclass) {
|
2018-06-26 10:14:12 +00:00
|
|
|
Node* promise =
|
|
|
|
HeapConstant(handle(native_context()->promise_function(), isolate()));
|
|
|
|
Node* new_target =
|
|
|
|
HeapConstant(handle(native_context()->array_function(), isolate()));
|
2018-02-19 13:31:18 +00:00
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
|
|
|
|
Node* executor = UndefinedConstant();
|
|
|
|
Node* construct =
|
|
|
|
graph()->NewNode(javascript()->Construct(3), promise, executor,
|
|
|
|
new_target, context, frame_state, effect, control);
|
|
|
|
|
|
|
|
Reduction r = Reduce(construct);
|
|
|
|
|
|
|
|
ASSERT_FALSE(r.Changed());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, PromiseConstructorBasic) {
|
2018-06-26 10:14:12 +00:00
|
|
|
Node* promise =
|
|
|
|
HeapConstant(handle(native_context()->promise_function(), isolate()));
|
2018-02-19 13:31:18 +00:00
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
|
|
|
|
Node* executor = UndefinedConstant();
|
|
|
|
Node* construct =
|
|
|
|
graph()->NewNode(javascript()->Construct(3), promise, executor, promise,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
|
|
|
|
Reduction r = Reduce(construct);
|
|
|
|
|
|
|
|
if (FLAG_experimental_inline_promise_constructor) {
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
} else {
|
|
|
|
ASSERT_FALSE(r.Changed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-21 11:38:35 +00:00
|
|
|
// Exactly the same as PromiseConstructorBasic which expects a reduction,
|
|
|
|
// except that we invalidate the protector cell.
|
2018-02-19 13:31:18 +00:00
|
|
|
TEST_F(JSCallReducerTest, PromiseConstructorWithHook) {
|
2018-06-26 10:14:12 +00:00
|
|
|
Node* promise =
|
|
|
|
HeapConstant(handle(native_context()->promise_function(), isolate()));
|
2018-02-19 13:31:18 +00:00
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
|
|
|
|
Node* executor = UndefinedConstant();
|
|
|
|
Node* construct =
|
|
|
|
graph()->NewNode(javascript()->Construct(3), promise, executor, promise,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
|
|
|
|
isolate()->InvalidatePromiseHookProtector();
|
|
|
|
|
|
|
|
Reduction r = Reduce(construct);
|
|
|
|
|
|
|
|
ASSERT_FALSE(r.Changed());
|
|
|
|
}
|
|
|
|
|
2018-02-21 11:38:35 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Math unaries
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
const char* kMathUnaries[] = {
|
|
|
|
"abs", "acos", "acosh", "asin", "asinh", "atan", "cbrt",
|
|
|
|
"ceil", "cos", "cosh", "exp", "expm1", "floor", "fround",
|
|
|
|
"log", "log1p", "log10", "log2", "round", "sign", "sin",
|
|
|
|
"sinh", "sqrt", "tan", "tanh", "trunc"};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathUnaryWithNumber) {
|
|
|
|
TRACED_FOREACH(const char*, fnc, kMathUnaries) {
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* jsfunction = MathFunction(fnc);
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(3), jsfunction, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(std::string(IrOpcode::Mnemonic(r.replacement()->opcode())),
|
|
|
|
op_name_for(fnc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Math binaries
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
const char* kMathBinaries[] = {"atan2", "pow"};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathBinaryWithNumber) {
|
|
|
|
TRACED_FOREACH(const char*, fnc, kMathBinaries) {
|
|
|
|
Node* jsfunction = MathFunction(fnc);
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* p1 = Parameter(Type::Any(), 0);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(4), jsfunction, UndefinedConstant(), p0,
|
|
|
|
p1, context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(std::string(IrOpcode::Mnemonic(r.replacement()->opcode())),
|
|
|
|
op_name_for(fnc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Math.clz32
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathClz32WithUnsigned32) {
|
|
|
|
Node* jsfunction = MathFunction("clz32");
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
|
|
|
|
Node* p0 = Parameter(Type::Unsigned32(), 0);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(3), jsfunction, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
2018-02-22 08:06:56 +00:00
|
|
|
EXPECT_THAT(r.replacement(),
|
|
|
|
IsNumberClz32(IsNumberToUint32(IsSpeculativeToNumber(p0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathClz32WithUnsigned32NoArg) {
|
|
|
|
Node* jsfunction = MathFunction("clz32");
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(2), jsfunction, UndefinedConstant(),
|
|
|
|
context, frame_state, effect, control);
|
2018-02-22 08:06:56 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsNumberConstant(32));
|
2018-02-21 11:38:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Math.imul
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathImulWithUnsigned32) {
|
|
|
|
Node* jsfunction = MathFunction("imul");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Unsigned32(), 0);
|
|
|
|
Node* p1 = Parameter(Type::Unsigned32(), 1);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(4), jsfunction, UndefinedConstant(), p0,
|
|
|
|
p1, context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(std::string(IrOpcode::Mnemonic(r.replacement()->opcode())),
|
|
|
|
op_name_for("imul"));
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Math.min
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathMinWithNoArguments) {
|
|
|
|
Node* jsfunction = MathFunction("min");
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(2), jsfunction, UndefinedConstant(),
|
|
|
|
context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsNumberConstant(V8_INFINITY));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathMinWithNumber) {
|
|
|
|
Node* jsfunction = MathFunction("min");
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(3), jsfunction, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsSpeculativeToNumber(p0));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathMinWithTwoArguments) {
|
|
|
|
Node* jsfunction = MathFunction("min");
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* p1 = Parameter(Type::Any(), 1);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(4), jsfunction, UndefinedConstant(), p0,
|
|
|
|
p1, context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsNumberMin(IsSpeculativeToNumber(p0),
|
|
|
|
IsSpeculativeToNumber(p1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Math.max
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathMaxWithNoArguments) {
|
|
|
|
Node* jsfunction = MathFunction("max");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(2), jsfunction, UndefinedConstant(),
|
|
|
|
context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathMaxWithNumber) {
|
|
|
|
Node* jsfunction = MathFunction("max");
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(3), jsfunction, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsSpeculativeToNumber(p0));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, MathMaxWithTwoArguments) {
|
|
|
|
Node* jsfunction = MathFunction("max");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* p1 = Parameter(Type::Any(), 1);
|
2018-02-22 14:41:23 +00:00
|
|
|
Node* call = graph()->NewNode(Call(4), jsfunction, UndefinedConstant(), p0,
|
|
|
|
p1, context, frame_state, effect, control);
|
2018-02-21 11:38:35 +00:00
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsNumberMax(IsSpeculativeToNumber(p0),
|
|
|
|
IsSpeculativeToNumber(p1)));
|
|
|
|
}
|
|
|
|
|
2018-02-23 13:03:27 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// String.fromCharCode
|
|
|
|
|
2018-03-23 13:03:34 +00:00
|
|
|
TEST_F(JSCallReducerTest, StringFromSingleCharCodeWithNumber) {
|
2018-02-23 13:03:27 +00:00
|
|
|
Node* function = StringFunction("fromCharCode");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* call = graph()->NewNode(Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
2018-03-23 13:03:34 +00:00
|
|
|
EXPECT_THAT(r.replacement(),
|
|
|
|
IsStringFromSingleCharCode(IsSpeculativeToNumber(p0)));
|
2018-02-23 13:03:27 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 13:03:34 +00:00
|
|
|
TEST_F(JSCallReducerTest, StringFromSingleCharCodeWithPlainPrimitive) {
|
2018-02-23 13:03:27 +00:00
|
|
|
Node* function = StringFunction("fromCharCode");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
|
|
|
|
Node* call = graph()->NewNode(Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
2018-03-23 13:03:34 +00:00
|
|
|
EXPECT_THAT(r.replacement(),
|
|
|
|
IsStringFromSingleCharCode(IsSpeculativeToNumber(p0)));
|
2018-02-23 13:03:27 +00:00
|
|
|
}
|
|
|
|
|
2018-03-16 08:36:57 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Number.isFinite
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, NumberIsFinite) {
|
|
|
|
Node* function = NumberFunction("isFinite");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* call = graph()->NewNode(Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsObjectIsFiniteNumber(p0));
|
|
|
|
}
|
|
|
|
|
2018-03-16 08:37:33 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Number.isInteger
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, NumberIsIntegerWithNumber) {
|
|
|
|
Node* function = NumberFunction("isInteger");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* call =
|
|
|
|
graph()->NewNode(javascript()->Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsObjectIsInteger(p0));
|
|
|
|
}
|
|
|
|
|
2018-03-16 12:56:59 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Number.isNaN
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, NumberIsNaNWithNumber) {
|
|
|
|
Node* function = NumberFunction("isNaN");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* call =
|
|
|
|
graph()->NewNode(javascript()->Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsObjectIsNaN(p0));
|
|
|
|
}
|
|
|
|
|
2018-03-21 12:04:47 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Number.isSafeInteger
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, NumberIsSafeIntegerWithIntegral32) {
|
|
|
|
Node* function = NumberFunction("isSafeInteger");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* call =
|
|
|
|
graph()->NewNode(javascript()->Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsObjectIsSafeInteger(p0));
|
|
|
|
}
|
|
|
|
|
2018-04-23 08:49:19 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// isFinite
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, GlobalIsFiniteWithNumber) {
|
|
|
|
Node* function = GlobalFunction("isFinite");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* call = graph()->NewNode(Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsNumberIsFinite(IsSpeculativeToNumber(p0)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// isNaN
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, GlobalIsNaN) {
|
|
|
|
Node* function = GlobalFunction("isNaN");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* call = graph()->NewNode(Call(3), function, UndefinedConstant(), p0,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsNumberIsNaN(IsSpeculativeToNumber(p0)));
|
|
|
|
}
|
|
|
|
|
2018-04-26 06:59:15 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Number.parseInt
|
|
|
|
|
|
|
|
TEST_F(JSCallReducerTest, NumberParseInt) {
|
|
|
|
Node* function = NumberFunction("parseInt");
|
|
|
|
|
|
|
|
Node* effect = graph()->start();
|
|
|
|
Node* control = graph()->start();
|
|
|
|
Node* context = UndefinedConstant();
|
|
|
|
Node* frame_state = graph()->start();
|
|
|
|
Node* p0 = Parameter(Type::Any(), 0);
|
|
|
|
Node* p1 = Parameter(Type::Any(), 1);
|
|
|
|
Node* call = graph()->NewNode(Call(4), function, UndefinedConstant(), p0, p1,
|
|
|
|
context, frame_state, effect, control);
|
|
|
|
Reduction r = Reduce(call);
|
|
|
|
|
|
|
|
ASSERT_TRUE(r.Changed());
|
|
|
|
EXPECT_THAT(r.replacement(), IsJSParseInt(p0, p1));
|
|
|
|
}
|
|
|
|
|
2018-02-19 13:31:18 +00:00
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|