[Interpreter] Add wide context slot load / store operations.

Adds wide context slot load / store operations. Adds LdaContextSlotWide
and StaContextSlotWide bytecodes.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#33211}
This commit is contained in:
rmcilroy 2016-01-11 08:37:53 -08:00 committed by Commit bot
parent 036e3e015f
commit 2e2e6b41b5
7 changed files with 111 additions and 6 deletions

View File

@ -766,6 +766,12 @@ void BytecodeGraphBuilder::VisitLdaContextSlot(
}
void BytecodeGraphBuilder::VisitLdaContextSlotWide(
const interpreter::BytecodeArrayIterator& iterator) {
VisitLdaContextSlot(iterator);
}
void BytecodeGraphBuilder::VisitStaContextSlot(
const interpreter::BytecodeArrayIterator& iterator) {
// TODO(mythria): LoadContextSlots are unrolled by the required depth when
@ -779,6 +785,12 @@ void BytecodeGraphBuilder::VisitStaContextSlot(
}
void BytecodeGraphBuilder::VisitStaContextSlotWide(
const interpreter::BytecodeArrayIterator& iterator) {
VisitStaContextSlot(iterator);
}
void BytecodeGraphBuilder::BuildLdaLookupSlot(
TypeofMode typeof_mode,
const interpreter::BytecodeArrayIterator& iterator) {

View File

@ -431,6 +431,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
if (FitsInIdx8Operand(slot_index)) {
Output(Bytecode::kLdaContextSlot, context.ToOperand(),
static_cast<uint8_t>(slot_index));
} else if (FitsInIdx16Operand(slot_index)) {
Output(Bytecode::kLdaContextSlotWide, context.ToOperand(),
static_cast<uint16_t>(slot_index));
} else {
UNIMPLEMENTED();
}
@ -444,6 +447,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
if (FitsInIdx8Operand(slot_index)) {
Output(Bytecode::kStaContextSlot, context.ToOperand(),
static_cast<uint8_t>(slot_index));
} else if (FitsInIdx16Operand(slot_index)) {
Output(Bytecode::kStaContextSlotWide, context.ToOperand(),
static_cast<uint16_t>(slot_index));
} else {
UNIMPLEMENTED();
}

View File

@ -67,6 +67,8 @@ namespace interpreter {
V(PopContext, OperandType::kReg8) \
V(LdaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
V(StaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
V(LdaContextSlotWide, OperandType::kReg8, OperandType::kIdx16) \
V(StaContextSlotWide, OperandType::kReg8, OperandType::kIdx16) \
\
/* Load-Store lookup slots */ \
V(LdaLookupSlot, OperandType::kIdx8) \

View File

@ -433,6 +433,15 @@ void Interpreter::DoLdaContextSlot(compiler::InterpreterAssembler* assembler) {
}
// LdaContextSlotWide <context> <slot_index>
//
// Load the object in |slot_index| of |context| into the accumulator.
void Interpreter::DoLdaContextSlotWide(
compiler::InterpreterAssembler* assembler) {
DoLdaContextSlot(assembler);
}
// StaContextSlot <context> <slot_index>
//
// Stores the object in the accumulator into |slot_index| of |context|.
@ -446,6 +455,15 @@ void Interpreter::DoStaContextSlot(compiler::InterpreterAssembler* assembler) {
}
// StaContextSlot <context> <slot_index>
//
// Stores the object in the accumulator into |slot_index| of |context|.
void Interpreter::DoStaContextSlotWide(
compiler::InterpreterAssembler* assembler) {
DoStaContextSlot(assembler);
}
void Interpreter::DoLoadLookupSlot(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) {
Node* index = __ BytecodeOperandIdx(0);

View File

@ -109,8 +109,12 @@ class BytecodeGeneratorHelper {
#error Unknown byte ordering
#endif
#define XSTR(A) #A
#define STR(A) XSTR(A)
#define COMMA() ,
#define SPACE()
#define UNIQUE_VAR() "var a" STR(__COUNTER__) " = 0;\n"
#define REPEAT_2(SEP, ...) \
__VA_ARGS__ SEP() __VA_ARGS__
@ -135,6 +139,16 @@ class BytecodeGeneratorHelper {
REPEAT_4(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__) SEP() \
__VA_ARGS__
#define REPEAT_249(SEP, ...) \
REPEAT_127(SEP, __VA_ARGS__) SEP() REPEAT_64(SEP, __VA_ARGS__) SEP() \
REPEAT_32(SEP, __VA_ARGS__) SEP() REPEAT_16(SEP, __VA_ARGS__) SEP() \
REPEAT_8(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__)
#define REPEAT_249_UNIQUE_VARS() \
UNIQUE_VAR() REPEAT_127(UNIQUE_VAR) UNIQUE_VAR() REPEAT_64(UNIQUE_VAR) \
UNIQUE_VAR() REPEAT_32(UNIQUE_VAR) UNIQUE_VAR() REPEAT_16(UNIQUE_VAR) \
UNIQUE_VAR() REPEAT_8(UNIQUE_VAR) UNIQUE_VAR() REPEAT_2(UNIQUE_VAR)
// Structure for containing expected bytecode snippets.
template<typename T, int C = 6>
struct ExpectedSnippet {
@ -4016,7 +4030,15 @@ TEST(ContextVariables) {
i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec);
int closure = Register::function_closure().index();
int new_target = Register::new_target().index();
int first_context_slot = Context::MIN_CONTEXT_SLOTS;
// The wide check below relies on MIN_CONTEXT_SLOTS + 3 + 249 == 256, if this
// ever changes, the REPEAT_XXX should be changed to output the correct number
// of unique variables to trigger the wide slot load / store.
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS + 3 + 249 == 256);
int wide_slot = first_context_slot + 3;
ExpectedSnippet<InstanceType> snippets[] = {
{"var a; return function() { a = 1; };",
1 * kPointerSize,
@ -4109,6 +4131,39 @@ TEST(ContextVariables) {
2,
{InstanceType::FIXED_ARRAY_TYPE,
InstanceType::SHARED_FUNCTION_INFO_TYPE}},
{"'use strict';\n"
REPEAT_249_UNIQUE_VARS()
"eval();"
"var b = 100;"
"return b",
3 * kPointerSize,
1,
1041,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
U8(1), //
B(PushContext), R(0), //
B(Ldar), THIS(1), //
B(StaContextSlot), R(0), U8(first_context_slot), //
B(CreateUnmappedArguments), //
B(StaContextSlot), R(0), U8(first_context_slot + 1), //
B(Ldar), R(new_target), //
B(StaContextSlot), R(0), U8(first_context_slot + 2), //
REPEAT_249(COMMA, //
B(LdaZero), //
B(StaContextSlot), R(0), U8(wide_slot++)), //
B(LdaUndefined), //
B(Star), R(2), //
B(LdaGlobalStrict), U8(0), U8(1), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(0), U8(0), //
B(LdaSmi8), U8(100), //
B(StaContextSlotWide), R(0), U16(256), //
B(LdaContextSlotWide), R(0), U16(256), //
B(Return), //
},
1,
{InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {

View File

@ -1944,7 +1944,11 @@ TEST(InterpreterContextVariables) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
std::pair<const char*, Handle<Object>> context_vars[] = {
std::ostringstream unique_vars;
for (int i = 0; i < 250; i++) {
unique_vars << "var a" << i << " = 0;";
}
std::pair<std::string, Handle<Object>> context_vars[] = {
std::make_pair("var a; (function() { a = 1; })(); return a;",
handle(Smi::FromInt(1), isolate)),
std::make_pair("var a = 10; (function() { a; })(); return a;",
@ -1959,10 +1963,14 @@ TEST(InterpreterContextVariables) {
"{ let b = 20; var c = function() { [a, b] };\n"
" return a + b; }",
handle(Smi::FromInt(30), isolate)),
std::make_pair("'use strict';" + unique_vars.str() +
"eval(); var b = 100; return b;",
handle(Smi::FromInt(100), isolate)),
};
for (size_t i = 0; i < arraysize(context_vars); i++) {
std::string source(InterpreterTester::SourceForBody(context_vars[i].first));
std::string source(
InterpreterTester::SourceForBody(context_vars[i].first.c_str()));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();

View File

@ -69,10 +69,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.StoreGlobal(name, 1, LanguageMode::STRICT);
// Emit context operations.
builder.PushContext(reg);
builder.PopContext(reg);
builder.LoadContextSlot(reg, 1);
builder.StoreContextSlot(reg, 1);
builder.PushContext(reg)
.PopContext(reg)
.LoadContextSlot(reg, 1)
.StoreContextSlot(reg, 1);
// Emit load / store property operations.
builder.LoadNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
@ -241,6 +241,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
.StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
// Emit wide context operations.
builder.LoadContextSlot(reg, 1024)
.StoreContextSlot(reg, 1024);
// Emit wide load / store lookup slots.
builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)