Commit 2c8340da authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add support for local context loads and stores.

Adds support for local context loads and stores. Also adds support for
creation of new block contexts (e.g., for let variables) and initializing
const / let variables with the hole appropriately.

Also adds some checks to ensure BytecodeArrayBuilder::context_count is set
appropriately and fixes tests to do so.

Adds the bytecode StaContextSlot.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31343}
parent 4b2fffae
......@@ -273,6 +273,12 @@ void BytecodeGraphBuilder::VisitLdaContextSlot(
}
void BytecodeGraphBuilder::VisitStaContextSlot(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLoadICSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
......
......@@ -305,6 +305,15 @@ Node* InterpreterAssembler::LoadContextSlot(Node* context, Node* slot_index) {
}
Node* InterpreterAssembler::StoreContextSlot(Node* context, Node* slot_index,
Node* value) {
Node* offset =
IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
Int32Constant(Context::kHeaderSize - kHeapObjectTag));
return raw_assembler_->Store(kMachAnyTagged, context, offset, value);
}
Node* InterpreterAssembler::LoadTypeFeedbackVector() {
Node* function = raw_assembler_->Load(
kMachAnyTagged, RegisterFileRawPointer(),
......
......@@ -97,6 +97,8 @@ class InterpreterAssembler {
// Load |slot_index| from |context|.
Node* LoadContextSlot(Node* context, Node* slot_index);
// Stores |value| into |slot_index| of |context|.
Node* StoreContextSlot(Node* context, Node* slot_index, Node* value);
// Load the TypeFeedbackVector for the current function.
Node* LoadTypeFeedbackVector();
......
......@@ -32,17 +32,11 @@ void BytecodeArrayBuilder::set_locals_count(int number_of_locals) {
}
int BytecodeArrayBuilder::locals_count() const { return local_register_count_; }
void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) {
parameter_count_ = number_of_parameters;
}
int BytecodeArrayBuilder::parameter_count() const { return parameter_count_; }
void BytecodeArrayBuilder::set_context_count(int number_of_contexts) {
context_register_count_ = number_of_contexts;
DCHECK_GE(local_register_count_, 0);
......@@ -64,20 +58,17 @@ Register BytecodeArrayBuilder::last_context_register() const {
Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
DCHECK_GE(parameter_index, 0);
DCHECK_LT(parameter_index, parameter_count_);
return Register::FromParameterIndex(parameter_index, parameter_count_);
return Register::FromParameterIndex(parameter_index, parameter_count());
}
Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
DCHECK_EQ(bytecode_generated_, false);
DCHECK_GE(parameter_count_, 0);
DCHECK_GE(local_register_count_, 0);
EnsureReturn();
int bytecode_size = static_cast<int>(bytecodes_.size());
int register_count = local_register_count_ + temporary_register_count_;
int register_count = fixed_register_count() + temporary_register_count_;
int frame_size = register_count * kPointerSize;
Factory* factory = isolate_->factory();
......@@ -90,7 +81,7 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
Handle<BytecodeArray> output =
factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size,
parameter_count_, constant_pool);
parameter_count(), constant_pool);
bytecode_generated_ = true;
return output;
}
......@@ -289,6 +280,19 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
int slot_index) {
DCHECK(slot_index >= 0);
if (FitsInIdx8Operand(slot_index)) {
Output(Bytecode::kStaContextSlot, context.ToOperand(),
static_cast<uint8_t>(slot_index));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
Register object, int feedback_slot, LanguageMode language_mode) {
Bytecode bytecode = BytecodeForLoadIC(language_mode);
......@@ -638,9 +642,8 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
int BytecodeArrayBuilder::BorrowTemporaryRegister() {
DCHECK_GE(local_register_count_, 0);
int temporary_reg_index = temporary_register_next_++;
int count = temporary_register_next_ - local_register_count_;
int count = temporary_register_next_ - fixed_register_count();
if (count > temporary_register_count_) {
temporary_register_count_ = count;
}
......@@ -671,8 +674,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
if (reg.is_function_context() || reg.is_function_closure()) {
return true;
} else if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count_);
return parameter_index >= 0 && parameter_index < parameter_count_;
int parameter_index = reg.ToParameterIndex(parameter_count());
return parameter_index >= 0 && parameter_index < parameter_count();
} else {
return (reg.index() >= 0 && reg.index() < temporary_register_next_);
}
......
......@@ -30,19 +30,31 @@ class BytecodeArrayBuilder {
// Set number of parameters expected by function.
void set_parameter_count(int number_of_params);
int parameter_count() const;
int parameter_count() const {
DCHECK_GE(parameter_count_, 0);
return parameter_count_;
}
// Set number of locals required for bytecode array.
void set_locals_count(int number_of_locals);
int locals_count() const;
int locals_count() const {
DCHECK_GE(local_register_count_, 0);
return local_register_count_;
}
// Set number of contexts required for bytecode array.
void set_context_count(int number_of_contexts);
int context_count() const;
int context_count() const {
DCHECK_GE(context_register_count_, 0);
return context_register_count_;
}
Register first_context_register() const;
Register last_context_register() const;
// Returns the number of fixed (non-temporary) registers.
int fixed_register_count() const { return context_count() + locals_count(); }
Register Parameter(int parameter_index) const;
// Constant loads to the accumulator.
......@@ -61,6 +73,9 @@ class BytecodeArrayBuilder {
// Load the object at |slot_index| in |context| into the accumulator.
BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index);
// Stores the object in the accumulator into |slot_index| of |context|.
BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index);
// Register-accumulator transfers.
BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
......
This diff is collapsed.
......@@ -33,6 +33,7 @@ class BytecodeGenerator : public AstVisitor {
class ControlScopeForIteration;
void MakeBytecodeBody();
Register NextContextRegister() const;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
......@@ -46,6 +47,9 @@ class BytecodeGenerator : public AstVisitor {
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
void VisitNewLocalFunctionContext();
void VisitBuildLocalActivationContext();
void VisitNewLocalBlockContext(Scope* scope);
void VisitFunctionClosureForContext();
void VisitSetHomeObject(Register value, Register home_object,
ObjectLiteralProperty* property, int slot_number = 0);
void VisitObjectLiteralAccessor(Register home_object,
......@@ -67,11 +71,13 @@ class BytecodeGenerator : public AstVisitor {
inline CompilationInfo* info() const { return info_; }
inline void set_info(CompilationInfo* info) { info_ = info; }
inline ControlScope* control_scope() const { return control_scope_; }
inline void set_control_scope(ControlScope* scope) { control_scope_ = scope; }
inline Register current_context() const { return current_context_; }
inline void set_current_context(Register context) {
current_context_ = context;
inline ControlScope* execution_control() const { return execution_control_; }
inline void set_execution_control(ControlScope* scope) {
execution_control_ = scope;
}
inline ContextScope* execution_context() const { return execution_context_; }
inline void set_execution_context(ContextScope* context) {
execution_context_ = context;
}
ZoneVector<Handle<Object>>* globals() { return &globals_; }
......@@ -85,9 +91,8 @@ class BytecodeGenerator : public AstVisitor {
CompilationInfo* info_;
Scope* scope_;
ZoneVector<Handle<Object>> globals_;
ControlScope* control_scope_;
Register current_context_;
ControlScope* execution_control_;
ContextScope* execution_context_;
};
} // namespace interpreter
......
......@@ -49,7 +49,10 @@ namespace interpreter {
V(StaGlobalStrict, OperandType::kIdx8) \
\
/* Context operations */ \
V(PushContext, OperandType::kReg8) \
V(PopContext, OperandType::kReg8) \
V(LdaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
V(StaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
\
/* Register-accumulator transfers */ \
V(Ldar, OperandType::kReg8) \
......@@ -69,10 +72,6 @@ namespace interpreter {
V(KeyedStoreICStrict, OperandType::kReg8, OperandType::kReg8, \
OperandType::kIdx8) \
\
/* Context operations */ \
V(PushContext, OperandType::kReg8) \
V(PopContext, OperandType::kReg8) \
\
/* Binary Operators */ \
V(Add, OperandType::kReg8) \
V(Sub, OperandType::kReg8) \
......@@ -210,6 +209,9 @@ class Register {
Register reg4 = Register(),
Register reg5 = Register());
bool operator==(const Register& o) const { return o.index() == index(); }
bool operator!=(const Register& o) const { return o.index() != index(); }
private:
static const int kIllegalIndex = kMaxInt;
......
......@@ -235,6 +235,19 @@ void Interpreter::DoLdaContextSlot(compiler::InterpreterAssembler* assembler) {
}
// StaContextSlot <context> <slot_index>
//
// Stores the object in the accumulator into |slot_index| of |context|.
void Interpreter::DoStaContextSlot(compiler::InterpreterAssembler* assembler) {
Node* value = __ GetAccumulator();
Node* reg_index = __ BytecodeOperandReg8(0);
Node* context = __ LoadRegister(reg_index);
Node* slot_index = __ BytecodeOperandIdx8(1);
__ StoreContextSlot(context, slot_index, value);
__ Dispatch();
}
void Interpreter::DoPropertyLoadIC(Callable ic,
compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code());
......
This diff is collapsed.
......@@ -98,6 +98,7 @@ Matcher<Node*> BytecodeGraphBuilderTest::IsTrueConstant() {
TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) {
array_builder()->set_locals_count(0);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadUndefined().Return();
......@@ -113,6 +114,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) {
TEST_F(BytecodeGraphBuilderTest, ReturnNull) {
array_builder()->set_locals_count(0);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadNull().Return();
......@@ -126,6 +128,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnNull) {
TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) {
array_builder()->set_locals_count(0);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadTheHole().Return();
......@@ -141,6 +144,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) {
TEST_F(BytecodeGraphBuilderTest, ReturnTrue) {
array_builder()->set_locals_count(0);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadTrue().Return();
......@@ -156,6 +160,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnTrue) {
TEST_F(BytecodeGraphBuilderTest, ReturnFalse) {
array_builder()->set_locals_count(0);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadFalse().Return();
......@@ -172,6 +177,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnFalse) {
TEST_F(BytecodeGraphBuilderTest, ReturnInt8) {
static const int kValue = 3;
array_builder()->set_locals_count(0);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadLiteral(Smi::FromInt(kValue)).Return();
......@@ -188,6 +194,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnInt8) {
TEST_F(BytecodeGraphBuilderTest, ReturnDouble) {
const double kValue = 0.123456789;
array_builder()->set_locals_count(0);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadLiteral(factory()->NewHeapNumber(kValue));
array_builder()->Return();
......@@ -204,6 +211,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnDouble) {
TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithParameters) {
array_builder()->set_locals_count(1);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(3);
array_builder()
->LoadAccumulatorWithRegister(array_builder()->Parameter(1))
......@@ -227,6 +235,7 @@ TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithRegister) {
static const int kLeft = -655371;
static const int kRight = +2000000;
array_builder()->set_locals_count(1);
array_builder()->set_context_count(0);
array_builder()->set_parameter_count(1);
array_builder()
->LoadLiteral(Smi::FromInt(kLeft))
......
......@@ -486,6 +486,24 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
}
TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
Node* context = m.Int32Constant(1);
Node* slot_index = m.Int32Constant(22);
Node* value = m.Int32Constant(100);
Node* store_context_slot = m.StoreContextSlot(context, slot_index, value);
Matcher<Node*> offset =
IsIntPtrAdd(IsWordShl(slot_index, IsInt32Constant(kPointerSizeLog2)),
IsInt32Constant(Context::kHeaderSize - kHeapObjectTag));
EXPECT_THAT(store_context_slot,
m.IsStore(StoreRepresentation(kMachAnyTagged, kNoWriteBarrier),
context, offset, value));
}
}
TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
......
......@@ -23,8 +23,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_locals_count(1);
builder.set_context_count(1);
builder.set_parameter_count(0);
CHECK_EQ(builder.locals_count(), 1);
CHECK_EQ(builder.context_count(), 1);
CHECK_EQ(builder.fixed_register_count(), 2);
// Emit constant loads.
builder.LoadLiteral(Smi::FromInt(0))
......@@ -49,6 +52,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.PushContext(reg);
builder.PopContext(reg);
builder.LoadContextSlot(reg, 1);
builder.StoreContextSlot(reg, 1);
// Emit load / store property operations.
builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY)
......@@ -134,7 +138,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Generate BytecodeArray.
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
CHECK_EQ(the_array->frame_size(), builder.locals_count() * kPointerSize);
CHECK_EQ(the_array->frame_size(),
builder.fixed_register_count() * kPointerSize);
// Build scorecard of bytecodes encountered in the BytecodeArray.
std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
......@@ -161,20 +166,23 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
for (int locals = 0; locals < 5; locals++) {
for (int temps = 0; temps < 3; temps++) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(locals);
builder.Return();
TemporaryRegisterScope temporaries(&builder);
for (int i = 0; i < temps; i++) {
temporaries.NewRegister();
for (int contexts = 0; contexts < 4; contexts++) {
for (int temps = 0; temps < 3; temps++) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(locals);
builder.set_context_count(contexts);
builder.Return();
TemporaryRegisterScope temporaries(&builder);
for (int i = 0; i < temps; i++) {
temporaries.NewRegister();
}
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
int total_registers = locals + contexts + temps;
CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
}
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
int total_registers = locals + temps;
CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
}
}
}
......@@ -184,6 +192,7 @@ TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
builder.Return();
int first;
......@@ -224,6 +233,7 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(10);
builder.set_locals_count(0);
builder.set_context_count(0);
Register param0(builder.Parameter(0));
Register param9(builder.Parameter(9));
......@@ -235,6 +245,7 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
Factory* factory = isolate()->factory();
Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
......@@ -260,6 +271,7 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
BytecodeLabel far0, far1, far2;
BytecodeLabel near0, near1, near2;
......@@ -328,6 +340,7 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
BytecodeLabel label0, label1, label2;
builder.Bind(&label0)
......@@ -379,6 +392,7 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
// Labels can only have 1 forward reference, but
// can be referred to mulitple times once bound.
......@@ -409,6 +423,7 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
for (int i = 0; i < kRepeats; i++) {
BytecodeLabel label;
......@@ -440,6 +455,7 @@ TEST_F(BytecodeArrayBuilderTest, ToBoolean) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
// Check ToBoolean emitted at start of block.
builder.EnterBlock().CastAccumulatorToBoolean();
......
......@@ -25,6 +25,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(3);
builder.set_locals_count(2);
builder.set_context_count(0);
Factory* factory = isolate()->factory();
Handle<HeapObject> heap_num_0 = factory->NewHeapNumber(2.718);
......
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