Commit 6eb5dae5 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Intepreter] Don't throw reference errors for globals in typeof.

Corrects LdaGlobal to deal with TypeofMode::INSIDE_TYPEOF so that it
doesn't throw a reference error on undefined globals.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31757}
parent babe50f0
......@@ -268,6 +268,18 @@ void BytecodeGraphBuilder::VisitLdaGlobalStrict(
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofStrict(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLdaGlobalSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
......@@ -280,6 +292,18 @@ void BytecodeGraphBuilder::VisitLdaGlobalStrictWide(
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitStaGlobalSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
......
......@@ -288,8 +288,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(
size_t name_index, int feedback_slot, LanguageMode language_mode) {
Bytecode bytecode = BytecodeForLoadGlobal(language_mode);
size_t name_index, int feedback_slot, LanguageMode language_mode,
TypeofMode typeof_mode) {
// TODO(rmcilroy): Potentially store language and typeof information in an
// operand rather than having extra bytecodes.
Bytecode bytecode = BytecodeForLoadGlobal(language_mode, typeof_mode);
if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) {
Output(bytecode, static_cast<uint8_t>(name_index),
static_cast<uint8_t>(feedback_slot));
......@@ -1030,6 +1033,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForWideOperands(Bytecode bytecode) {
return Bytecode::kLdaGlobalSloppyWide;
case Bytecode::kLdaGlobalStrict:
return Bytecode::kLdaGlobalStrictWide;
case Bytecode::kLdaGlobalInsideTypeofSloppy:
return Bytecode::kLdaGlobalInsideTypeofSloppyWide;
case Bytecode::kLdaGlobalInsideTypeofStrict:
return Bytecode::kLdaGlobalInsideTypeofStrictWide;
case Bytecode::kStaGlobalSloppy:
return Bytecode::kStaGlobalSloppyWide;
case Bytecode::kStaGlobalStrict:
......@@ -1108,13 +1115,17 @@ Bytecode BytecodeArrayBuilder::BytecodeForKeyedStoreIC(
// static
Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(
LanguageMode language_mode) {
Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(LanguageMode language_mode,
TypeofMode typeof_mode) {
switch (language_mode) {
case SLOPPY:
return Bytecode::kLdaGlobalSloppy;
return typeof_mode == INSIDE_TYPEOF
? Bytecode::kLdaGlobalInsideTypeofSloppy
: Bytecode::kLdaGlobalSloppy;
case STRICT:
return Bytecode::kLdaGlobalStrict;
return typeof_mode == INSIDE_TYPEOF
? Bytecode::kLdaGlobalInsideTypeofStrict
: Bytecode::kLdaGlobalStrict;
case STRONG:
UNIMPLEMENTED();
default:
......
......@@ -82,7 +82,8 @@ class BytecodeArrayBuilder {
// Global loads to the accumulator and stores from the accumulator.
BytecodeArrayBuilder& LoadGlobal(size_t name_index, int feedback_slot,
LanguageMode language_mode);
LanguageMode language_mode,
TypeofMode typeof_mode);
BytecodeArrayBuilder& StoreGlobal(size_t name_index, int feedback_slot,
LanguageMode language_mode);
......@@ -208,7 +209,8 @@ class BytecodeArrayBuilder {
static Bytecode BytecodeForKeyedLoadIC(LanguageMode language_mode);
static Bytecode BytecodeForStoreIC(LanguageMode language_mode);
static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode);
static Bytecode BytecodeForLoadGlobal(LanguageMode language_mode);
static Bytecode BytecodeForLoadGlobal(LanguageMode language_mode,
TypeofMode typeof_mode);
static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode);
static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
static Bytecode BytecodeForDelete(LanguageMode language_mode);
......
......@@ -1193,7 +1193,8 @@ void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
void BytecodeGenerator::VisitVariableLoad(Variable* variable,
FeedbackVectorSlot slot) {
FeedbackVectorSlot slot,
TypeofMode typeof_mode) {
switch (variable->location()) {
case VariableLocation::LOCAL: {
Register source(Register(variable->index()));
......@@ -1210,7 +1211,8 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: {
size_t name_index = builder()->GetConstantPoolEntry(variable->name());
builder()->LoadGlobal(name_index, feedback_index(slot), language_mode());
builder()->LoadGlobal(name_index, feedback_index(slot), language_mode(),
typeof_mode);
execution_result()->SetResultInAccumulator();
break;
}
......@@ -1247,16 +1249,16 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
void BytecodeGenerator::VisitVariableLoadForAccumulatorValue(
Variable* variable, FeedbackVectorSlot slot) {
Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) {
AccumulatorResultScope accumulator_result(this);
VisitVariableLoad(variable, slot);
VisitVariableLoad(variable, slot, typeof_mode);
}
Register BytecodeGenerator::VisitVariableLoadForRegisterValue(
Variable* variable, FeedbackVectorSlot slot) {
Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) {
RegisterResultScope register_scope(this);
VisitVariableLoad(variable, slot);
VisitVariableLoad(variable, slot, typeof_mode);
return register_scope.ResultRegister();
}
......@@ -1616,9 +1618,15 @@ void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
// TODO(rmcilroy): Set TypeofMode to INSIDE_TYPEOF for any loadICs performed
// while visiting the expression.
VisitForAccumulatorValue(expr->expression());
if (expr->expression()->IsVariableProxy()) {
// Typeof does not throw a reference error on global variables, hence we
// perform a non-contextual load in case the operand is a variable proxy.
VariableProxy* proxy = expr->expression()->AsVariableProxy();
VisitVariableLoadForAccumulatorValue(
proxy->var(), proxy->VariableFeedbackSlot(), INSIDE_TYPEOF);
} else {
VisitForAccumulatorValue(expr->expression());
}
builder()->TypeOf();
execution_result()->SetResultInAccumulator();
}
......
......@@ -60,11 +60,14 @@ class BytecodeGenerator : public AstVisitor {
void VisitPropertyLoad(Register obj, Property* expr);
void VisitPropertyLoadForAccumulator(Register obj, Property* expr);
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
void VisitVariableLoadForAccumulatorValue(Variable* variable,
FeedbackVectorSlot slot);
MUST_USE_RESULT Register VisitVariableLoadForRegisterValue(
Variable* variable, FeedbackVectorSlot slot);
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot,
TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
void VisitVariableLoadForAccumulatorValue(
Variable* variable, FeedbackVectorSlot slot,
TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
MUST_USE_RESULT Register
VisitVariableLoadForRegisterValue(Variable* variable, FeedbackVectorSlot slot,
TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
void VisitArgumentsObject(Variable* variable);
......
......@@ -47,8 +47,12 @@ namespace interpreter {
/* Globals */ \
V(LdaGlobalSloppy, OperandType::kIdx8, OperandType::kIdx8) \
V(LdaGlobalStrict, OperandType::kIdx8, OperandType::kIdx8) \
V(LdaGlobalInsideTypeofSloppy, OperandType::kIdx8, OperandType::kIdx8) \
V(LdaGlobalInsideTypeofStrict, OperandType::kIdx8, OperandType::kIdx8) \
V(LdaGlobalSloppyWide, OperandType::kIdx16, OperandType::kIdx16) \
V(LdaGlobalStrictWide, OperandType::kIdx16, OperandType::kIdx16) \
V(LdaGlobalInsideTypeofSloppyWide, OperandType::kIdx16, OperandType::kIdx16) \
V(LdaGlobalInsideTypeofStrictWide, OperandType::kIdx16, OperandType::kIdx16) \
V(StaGlobalSloppy, OperandType::kIdx8, OperandType::kIdx8) \
V(StaGlobalStrict, OperandType::kIdx8, OperandType::kIdx8) \
V(StaGlobalSloppyWide, OperandType::kIdx16, OperandType::kIdx16) \
......
......@@ -243,6 +243,30 @@ void Interpreter::DoLdaGlobalStrict(compiler::InterpreterAssembler* assembler) {
}
// LdaGlobalInsideTypeofSloppy <name_index> <slot>
//
// Load the global with name in constant pool entry <name_index> into the
// accumulator using FeedBackVector slot <slot> in sloppy mode.
void Interpreter::DoLdaGlobalInsideTypeofSloppy(
compiler::InterpreterAssembler* assembler) {
Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, INSIDE_TYPEOF,
SLOPPY, UNINITIALIZED);
DoLoadGlobal(ic, assembler);
}
// LdaGlobalInsideTypeofStrict <name_index> <slot>
//
// Load the global with name in constant pool entry <name_index> into the
// accumulator using FeedBackVector slot <slot> in strict mode.
void Interpreter::DoLdaGlobalInsideTypeofStrict(
compiler::InterpreterAssembler* assembler) {
Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, INSIDE_TYPEOF,
STRICT, UNINITIALIZED);
DoLoadGlobal(ic, assembler);
}
// LdaGlobalSloppyWide <name_index> <slot>
//
// Load the global with name in constant pool entry <name_index> into the
......@@ -267,6 +291,30 @@ void Interpreter::DoLdaGlobalStrictWide(
}
// LdaGlobalInsideTypeofSloppyWide <name_index> <slot>
//
// Load the global with name in constant pool entry <name_index> into the
// accumulator using FeedBackVector slot <slot> in sloppy mode.
void Interpreter::DoLdaGlobalInsideTypeofSloppyWide(
compiler::InterpreterAssembler* assembler) {
Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, INSIDE_TYPEOF,
SLOPPY, UNINITIALIZED);
DoLoadGlobal(ic, assembler);
}
// LdaGlobalInsideTypeofSloppyWide <name_index> <slot>
//
// Load the global with name in constant pool entry <name_index> into the
// accumulator using FeedBackVector slot <slot> in strict mode.
void Interpreter::DoLdaGlobalInsideTypeofStrictWide(
compiler::InterpreterAssembler* assembler) {
Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, INSIDE_TYPEOF,
STRICT, UNINITIALIZED);
DoLoadGlobal(ic, assembler);
}
void Interpreter::DoStoreGlobal(Callable ic,
compiler::InterpreterAssembler* assembler) {
// Get the global object.
......
......@@ -2455,19 +2455,6 @@ TEST(UnaryOperators) {
},
1,
{1234}},
{"var x = 13;"
"return typeof(x);",
kPointerSize,
1,
8,
{
B(LdaSmi8), U8(13), //
B(Star), R(0), // TODO(oth): Ldar R(X) following Star R(X)
B(Ldar), R(0), // could be culled in bytecode array builder.
B(TypeOf), //
B(Return), //
},
0},
{"var x = 13;"
"return ~x;",
1 * kPointerSize,
......@@ -2516,6 +2503,73 @@ TEST(UnaryOperators) {
}
TEST(Typeof) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
Zone zone;
FeedbackVectorSpec feedback_spec(&zone);
FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot();
Handle<i::TypeFeedbackVector> vector =
i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec);
ExpectedSnippet<const char*> snippets[] = {
{"function f() {\n"
" var x = 13;\n"
" return typeof(x);\n"
"}; f();",
kPointerSize,
1,
8,
{
B(LdaSmi8), U8(13), //
B(Star), R(0), // TODO(oth): Ldar R(X) following Star R(X)
B(Ldar), R(0), // could be culled in bytecode array builder.
B(TypeOf), //
B(Return), //
}},
{"var x = 13;\n"
"function f() {\n"
" return typeof(x);\n"
"}; f();",
0,
1,
5,
{
B(LdaGlobalInsideTypeofSloppy), U8(0), //
U8(vector->GetIndex(slot)), //
B(TypeOf), //
B(Return), //
},
1,
{"x"}},
{"var x = 13;\n"
"function f() {\n"
" 'use strict';\n"
" return typeof(x);\n"
"}; f();",
0,
1,
5,
{
B(LdaGlobalInsideTypeofStrict), U8(0), //
U8(vector->GetIndex(slot)), //
B(TypeOf), //
B(Return), //
},
1,
{"x"}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunction(snippets[i].code_snippet);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
TEST(Delete) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
......
......@@ -1640,38 +1640,29 @@ TEST(InterpreterUnaryNotNonBoolean) {
}
TEST(InterpreterTypeOf) {
TEST(InterpreterTypeof) {
HandleAndZoneScope handles;
i::Factory* factory = handles.main_isolate()->factory();
std::pair<Handle<Object>, const char*> object_type_tuples[] = {
std::make_pair(factory->undefined_value(), "undefined"),
std::make_pair(factory->null_value(), "object"),
std::make_pair(factory->true_value(), "boolean"),
std::make_pair(factory->false_value(), "boolean"),
std::make_pair(factory->NewNumber(9.1), "number"),
std::make_pair(factory->NewNumberFromInt(7771), "number"),
std::make_pair(
Handle<Object>::cast(factory->NewStringFromStaticChars("hello")),
"string"),
std::pair<const char*, const char*> typeof_vals[] = {
std::make_pair("return typeof undefined;", "undefined"),
std::make_pair("return typeof null;", "object"),
std::make_pair("return typeof true;", "boolean"),
std::make_pair("return typeof false;", "boolean"),
std::make_pair("return typeof 9.1;", "number"),
std::make_pair("return typeof 7771;", "number"),
std::make_pair("return typeof 'hello';", "string"),
std::make_pair("return typeof global_unallocated;", "undefined"),
};
for (size_t i = 0; i < arraysize(object_type_tuples); i++) {
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
Register r0(0);
builder.set_locals_count(0);
builder.set_context_count(0);
builder.set_parameter_count(0);
LoadAny(&builder, factory, object_type_tuples[i].first);
builder.TypeOf();
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
for (size_t i = 0; i < arraysize(typeof_vals); i++) {
std::string source(InterpreterTester::SourceForBody(typeof_vals[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<v8::internal::String> return_value =
Handle<v8::internal::String>::cast(callable().ToHandleChecked());
auto actual = return_value->ToCString();
CHECK_EQ(strcmp(&actual[0], object_type_tuples[i].second), 0);
CHECK_EQ(strcmp(&actual[0], typeof_vals[i].second), 0);
}
}
......
......@@ -44,14 +44,19 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg);
// Emit global load / store operations.
builder.LoadGlobal(0, 1, LanguageMode::SLOPPY)
.LoadGlobal(0, 1, LanguageMode::STRICT)
builder.LoadGlobal(0, 1, LanguageMode::SLOPPY, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadGlobal(0, 1, LanguageMode::STRICT, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadGlobal(0, 1, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF)
.LoadGlobal(0, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF)
.StoreGlobal(0, 1, LanguageMode::SLOPPY)
.StoreGlobal(0, 1, LanguageMode::STRICT);
// Emit wide global load / store operations.
builder.LoadGlobal(0, 1024, LanguageMode::SLOPPY)
.LoadGlobal(1024, 1, LanguageMode::STRICT)
builder.LoadGlobal(0, 1024, LanguageMode::SLOPPY,
TypeofMode::NOT_INSIDE_TYPEOF)
.LoadGlobal(1024, 1, LanguageMode::STRICT, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadGlobal(0, 1024, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF)
.LoadGlobal(1024, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF)
.StoreGlobal(0, 1024, LanguageMode::SLOPPY)
.StoreGlobal(1024, 1, LanguageMode::STRICT);
......
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