[turbofan] Add language mode to JSCallFunction operator.

Also do some drive-by-cleanup to the unittests.

R=svenpanne@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#28066}
This commit is contained in:
Benedikt Meurer 2015-04-27 12:44:47 +02:00
parent a4b7d45c7b
commit 2d827809e0
4 changed files with 102 additions and 92 deletions

View File

@ -1293,8 +1293,9 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
// result is either the string key or Smi(0) indicating the property
// is gone.
Node* res = NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
function, obj, value);
Node* res = NewNode(
javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS, language_mode()),
function, obj, value);
PrepareFrameState(res, stmt->FilterId(), OutputFrameStateCombine::Push());
Node* property_missing =
NewNode(javascript()->StrictEqual(), res, jsgraph()->ZeroConstant());
@ -2196,7 +2197,8 @@ void AstGraphBuilder::VisitCall(Call* expr) {
}
// Create node to perform the function call.
const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
const Operator* call =
javascript()->CallFunction(args->length() + 2, flags, language_mode());
Node* value = ProcessArguments(call, args->length() + 2);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
@ -2240,7 +2242,8 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
VisitForValues(args);
// Create node to perform the JS runtime call.
const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
const Operator* call =
javascript()->CallFunction(args->length() + 2, flags, language_mode());
Node* value = ProcessArguments(call, args->length() + 2);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);

View File

@ -14,25 +14,8 @@ namespace v8 {
namespace internal {
namespace compiler {
bool operator==(CallFunctionParameters const& lhs,
CallFunctionParameters const& rhs) {
return lhs.arity() == rhs.arity() && lhs.flags() == rhs.flags();
}
bool operator!=(CallFunctionParameters const& lhs,
CallFunctionParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(CallFunctionParameters const& p) {
return base::hash_combine(p.arity(), p.flags());
}
std::ostream& operator<<(std::ostream& os, CallFunctionParameters const& p) {
return os << p.arity() << ", " << p.flags();
return os << p.arity() << ", " << p.flags() << ", " << p.language_mode();
}
@ -354,8 +337,9 @@ CACHED_OP_LIST_WITH_LANGUAGE_MODE(CACHED_WITH_LANGUAGE_MODE)
const Operator* JSOperatorBuilder::CallFunction(size_t arity,
CallFunctionFlags flags) {
CallFunctionParameters parameters(arity, flags);
CallFunctionFlags flags,
LanguageMode language_mode) {
CallFunctionParameters parameters(arity, flags, language_mode);
return new (zone()) Operator1<CallFunctionParameters>( // --
IrOpcode::kJSCallFunction, Operator::kNoProperties, // opcode
"JSCallFunction", // name

View File

@ -21,19 +21,35 @@ struct JSOperatorGlobalCache;
// used as a parameter by JSCallFunction operators.
class CallFunctionParameters final {
public:
CallFunctionParameters(size_t arity, CallFunctionFlags flags)
: arity_(arity), flags_(flags) {}
CallFunctionParameters(size_t arity, CallFunctionFlags flags,
LanguageMode language_mode)
: bit_field_(ArityField::encode(arity) | FlagsField::encode(flags) |
LanguageModeField::encode(language_mode)) {}
size_t arity() const { return arity_; }
CallFunctionFlags flags() const { return flags_; }
size_t arity() const { return ArityField::decode(bit_field_); }
CallFunctionFlags flags() const { return FlagsField::decode(bit_field_); }
LanguageMode language_mode() const {
return LanguageModeField::decode(bit_field_);
}
bool operator==(CallFunctionParameters const& that) const {
return this->bit_field_ == that.bit_field_;
}
bool operator!=(CallFunctionParameters const& that) const {
return !(*this == that);
}
private:
const size_t arity_;
const CallFunctionFlags flags_;
};
friend size_t hash_value(CallFunctionParameters const& p) {
return p.bit_field_;
}
bool operator==(CallFunctionParameters const&, CallFunctionParameters const&);
bool operator!=(CallFunctionParameters const&, CallFunctionParameters const&);
typedef BitField<unsigned, 0, 28> ArityField;
typedef BitField<CallFunctionFlags, 28, 2> FlagsField;
typedef BitField<LanguageMode, 30, 2> LanguageModeField;
const uint32_t bit_field_;
};
size_t hash_value(CallFunctionParameters const&);
@ -273,7 +289,8 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* CreateLiteralArray(int literal_flags);
const Operator* CreateLiteralObject(int literal_flags);
const Operator* CallFunction(size_t arity, CallFunctionFlags flags);
const Operator* CallFunction(size_t arity, CallFunctionFlags flags,
LanguageMode language_mode);
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
const Operator* CallConstruct(int arguments);

View File

@ -30,7 +30,7 @@ class JSBuiltinReducerTest : public TypedGraphTest {
return reducer.Reduce(node);
}
Handle<JSFunction> MathFunction(const char* name) {
Node* MathFunction(const char* name) {
Handle<Object> m =
JSObject::GetProperty(isolate()->global_object(),
isolate()->factory()->NewStringFromAsciiChecked(
@ -39,7 +39,7 @@ class JSBuiltinReducerTest : public TypedGraphTest {
JSObject::GetProperty(
m, isolate()->factory()->NewStringFromAsciiChecked(name))
.ToHandleChecked());
return f;
return HeapConstant(Unique<JSFunction>::CreateUninitialized(f));
}
JSOperatorBuilder* javascript() { return &javascript_; }
@ -51,6 +51,15 @@ class JSBuiltinReducerTest : public TypedGraphTest {
namespace {
Type* const kIntegral32Types[] = {Type::UnsignedSmall(), Type::Negative32(),
Type::Unsigned31(), Type::SignedSmall(),
Type::Signed32(), Type::Unsigned32(),
Type::Integral32()};
const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG};
// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
Type* const kNumberTypes[] = {
Type::UnsignedSmall(), Type::Negative32(), Type::Unsigned31(),
@ -66,56 +75,55 @@ Type* const kNumberTypes[] = {
TEST_F(JSBuiltinReducerTest, MathMax0) {
Handle<JSFunction> f = MathFunction("max");
Node* function = MathFunction("max");
Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
Node* call =
graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS),
fun, UndefinedConstant());
Reduction r = Reduce(call);
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Node* call = graph()->NewNode(
javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS, language_mode),
function, UndefinedConstant());
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
}
}
TEST_F(JSBuiltinReducerTest, MathMax1) {
Handle<JSFunction> f = MathFunction("max");
Node* function = MathFunction("max");
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
Node* call =
graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
fun, UndefinedConstant(), p0);
Reduction r = Reduce(call);
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(
javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS, language_mode),
function, UndefinedConstant(), p0);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), p0);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), p0);
}
}
}
TEST_F(JSBuiltinReducerTest, MathMax2) {
Handle<JSFunction> f = MathFunction("max");
Node* function = MathFunction("max");
TRACED_FOREACH(Type*, t0, kNumberTypes) {
TRACED_FOREACH(Type*, t1, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1);
Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
Node* call = graph()->NewNode(
javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
UndefinedConstant(), p0, p1);
Reduction r = Reduce(call);
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
TRACED_FOREACH(Type*, t0, kIntegral32Types) {
TRACED_FOREACH(Type*, t1, kIntegral32Types) {
Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1);
Node* call =
graph()->NewNode(javascript()->CallFunction(
4, NO_CALL_FUNCTION_FLAGS, language_mode),
function, UndefinedConstant(), p0, p1);
Reduction r = Reduce(call);
if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSelect(kMachNone, IsNumberLessThan(p1, p0), p0, p1));
} else {
ASSERT_FALSE(r.Changed());
EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
}
}
}
@ -127,24 +135,21 @@ TEST_F(JSBuiltinReducerTest, MathMax2) {
TEST_F(JSBuiltinReducerTest, MathImul) {
Handle<JSFunction> f = MathFunction("imul");
Node* function = MathFunction("imul");
TRACED_FOREACH(Type*, t0, kNumberTypes) {
TRACED_FOREACH(Type*, t1, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1);
Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
Node* call = graph()->NewNode(
javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
UndefinedConstant(), p0, p1);
Reduction r = Reduce(call);
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
TRACED_FOREACH(Type*, t0, kIntegral32Types) {
TRACED_FOREACH(Type*, t1, kIntegral32Types) {
Node* p0 = Parameter(t0, 0);
Node* p1 = Parameter(t1, 1);
Node* call =
graph()->NewNode(javascript()->CallFunction(
4, NO_CALL_FUNCTION_FLAGS, language_mode),
function, UndefinedConstant(), p0, p1);
Reduction r = Reduce(call);
if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
} else {
ASSERT_FALSE(r.Changed());
EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
}
}
}
@ -156,18 +161,19 @@ TEST_F(JSBuiltinReducerTest, MathImul) {
TEST_F(JSBuiltinReducerTest, MathFround) {
Handle<JSFunction> f = MathFunction("fround");
Node* function = MathFunction("fround");
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
Node* call =
graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
fun, UndefinedConstant(), p0);
Reduction r = Reduce(call);
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(
javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS, language_mode),
function, UndefinedConstant(), p0);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0));
}
}
}