[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:
parent
036e3e015f
commit
2e2e6b41b5
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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++) {
|
||||
|
@ -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<>();
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user