Commit 688eacda authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add support for global declarations and load/store of global variables

Implements support for declaring global variables. Also adds support for loading
from and storing to both global and unallocated global variables.  Adds the
following bytecodes:
 - StoreGlobal
 - LoadContextSlot

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31166}
parent f29705db
...@@ -255,6 +255,18 @@ void BytecodeGraphBuilder::VisitLdaGlobal( ...@@ -255,6 +255,18 @@ void BytecodeGraphBuilder::VisitLdaGlobal(
} }
void BytecodeGraphBuilder::VisitStaGlobal(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLdaContextSlot(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLoadICSloppy( void BytecodeGraphBuilder::VisitLoadICSloppy(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); UNIMPLEMENTED();
......
...@@ -291,14 +291,11 @@ Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) { ...@@ -291,14 +291,11 @@ Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) {
} }
Node* InterpreterAssembler::LoadContextSlot(Node* context, int slot_index) { Node* InterpreterAssembler::LoadContextSlot(Node* context, Node* slot_index) {
return raw_assembler_->Load(kMachAnyTagged, context, Node* offset =
IntPtrConstant(Context::SlotOffset(slot_index))); IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
} Int32Constant(Context::kHeaderSize - kHeapObjectTag));
return raw_assembler_->Load(kMachAnyTagged, context, offset);
Node* InterpreterAssembler::LoadContextSlot(int slot_index) {
return LoadContextSlot(ContextTaggedPointer(), slot_index);
} }
...@@ -314,8 +311,7 @@ Node* InterpreterAssembler::LoadTypeFeedbackVector() { ...@@ -314,8 +311,7 @@ Node* InterpreterAssembler::LoadTypeFeedbackVector() {
} }
Node* InterpreterAssembler::CallN(CallDescriptor* descriptor, Node* InterpreterAssembler::CallN(CallDescriptor* descriptor, Node* code_target,
Node* code_target,
Node** args) { Node** args) {
Node* stack_pointer_before_call = nullptr; Node* stack_pointer_before_call = nullptr;
if (FLAG_debug_code) { if (FLAG_debug_code) {
...@@ -508,8 +504,8 @@ void InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) { ...@@ -508,8 +504,8 @@ void InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) {
} }
void InterpreterAssembler::AbortIfWordNotEqual( void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs,
Node* lhs, Node* rhs, BailoutReason bailout_reason) { BailoutReason bailout_reason) {
RawMachineAssembler::Label match, no_match; RawMachineAssembler::Label match, no_match;
Node* condition = raw_assembler_->WordEqual(lhs, rhs); Node* condition = raw_assembler_->WordEqual(lhs, rhs);
raw_assembler_->Branch(condition, &match, &no_match); raw_assembler_->Branch(condition, &match, &no_match);
......
...@@ -90,11 +90,8 @@ class InterpreterAssembler { ...@@ -90,11 +90,8 @@ class InterpreterAssembler {
// Load a field from an object on the heap. // Load a field from an object on the heap.
Node* LoadObjectField(Node* object, int offset); Node* LoadObjectField(Node* object, int offset);
// Load |slot_index| from a context. // Load |slot_index| from |context|.
Node* LoadContextSlot(Node* context, int slot_index); Node* LoadContextSlot(Node* context, Node* slot_index);
// Load |slot_index| from the current context.
Node* LoadContextSlot(int slot_index);
// Load the TypeFeedbackVector for the current function. // Load the TypeFeedbackVector for the current function.
Node* LoadTypeFeedbackVector(); Node* LoadTypeFeedbackVector();
......
...@@ -181,6 +181,7 @@ class InterpreterFrameConstants : public AllStatic { ...@@ -181,6 +181,7 @@ class InterpreterFrameConstants : public AllStatic {
static const int kLastParamFromRegisterPointer = static const int kLastParamFromRegisterPointer =
StandardFrameConstants::kFixedFrameSize + kPointerSize; StandardFrameConstants::kFixedFrameSize + kPointerSize;
static const int kFunctionFromRegisterPointer = kPointerSize; static const int kFunctionFromRegisterPointer = kPointerSize;
static const int kContextFromRegisterPointer = 2 * kPointerSize;
}; };
......
...@@ -241,6 +241,35 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int slot_index) { ...@@ -241,6 +241,35 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int slot_index) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
int slot_index, LanguageMode language_mode) {
if (!is_sloppy(language_mode)) {
UNIMPLEMENTED();
}
DCHECK(slot_index >= 0);
if (FitsInIdx8Operand(slot_index)) {
Output(Bytecode::kStaGlobal, static_cast<uint8_t>(slot_index));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
int slot_index) {
DCHECK(slot_index >= 0);
if (FitsInIdx8Operand(slot_index)) {
Output(Bytecode::kLdaContextSlot, context.ToOperand(),
static_cast<uint8_t>(slot_index));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
Register object, int feedback_slot, LanguageMode language_mode) { Register object, int feedback_slot, LanguageMode language_mode) {
Bytecode bytecode = BytecodeForLoadIC(language_mode); Bytecode bytecode = BytecodeForLoadIC(language_mode);
...@@ -542,7 +571,9 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, ...@@ -542,7 +571,9 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
return static_cast<uint8_t>(operand_value) == operand_value; return static_cast<uint8_t>(operand_value) == operand_value;
case OperandType::kReg8: { case OperandType::kReg8: {
Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value)); Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value));
if (reg.is_parameter()) { if (reg.is_function_context()) {
return true;
} else if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count_); int parameter_index = reg.ToParameterIndex(parameter_count_);
return parameter_index >= 0 && parameter_index < parameter_count_; return parameter_index >= 0 && parameter_index < parameter_count_;
} else { } else {
......
...@@ -47,8 +47,12 @@ class BytecodeArrayBuilder { ...@@ -47,8 +47,12 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& LoadTrue(); BytecodeArrayBuilder& LoadTrue();
BytecodeArrayBuilder& LoadFalse(); BytecodeArrayBuilder& LoadFalse();
// Global loads to accumulator. // Global loads to accumulator and stores from accumulator.
BytecodeArrayBuilder& LoadGlobal(int slot_index); BytecodeArrayBuilder& LoadGlobal(int slot_index);
BytecodeArrayBuilder& StoreGlobal(int slot_index, LanguageMode language_mode);
// Load the object at |slot_index| in |context| into the accumulator.
BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index);
// Register-accumulator transfers. // Register-accumulator transfers.
BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg); BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
......
...@@ -93,7 +93,9 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) ...@@ -93,7 +93,9 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
: builder_(isolate, zone), : builder_(isolate, zone),
info_(nullptr), info_(nullptr),
scope_(nullptr), scope_(nullptr),
control_scope_(nullptr) { globals_(0, zone),
control_scope_(nullptr),
current_context_(Register::function_context()) {
InitializeAstVisitor(isolate, zone); InitializeAstVisitor(isolate, zone);
} }
...@@ -145,11 +147,21 @@ void BytecodeGenerator::VisitBlock(Block* node) { ...@@ -145,11 +147,21 @@ void BytecodeGenerator::VisitBlock(Block* node) {
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
Variable* variable = decl->proxy()->var(); Variable* variable = decl->proxy()->var();
VariableMode mode = decl->mode();
bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
if (hole_init) {
UNIMPLEMENTED();
}
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::GLOBAL: case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: case VariableLocation::UNALLOCATED: {
UNIMPLEMENTED(); Handle<Oddball> value = variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
: isolate()->factory()->undefined_value();
globals()->push_back(variable->name());
globals()->push_back(value);
break; break;
}
case VariableLocation::PARAMETER: case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: case VariableLocation::LOCAL:
// Details stored in scope, i.e. variable index. // Details stored in scope, i.e. variable index.
...@@ -163,7 +175,24 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { ...@@ -163,7 +175,24 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
UNIMPLEMENTED(); Variable* variable = decl->proxy()->var();
switch (variable->location()) {
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: {
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
decl->fun(), info()->script(), info());
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals()->push_back(variable->name());
globals()->push_back(function);
break;
}
case VariableLocation::PARAMETER:
case VariableLocation::LOCAL:
case VariableLocation::CONTEXT:
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
}
} }
...@@ -177,6 +206,34 @@ void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) { ...@@ -177,6 +206,34 @@ void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
} }
void BytecodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
DCHECK(globals()->empty());
AstVisitor::VisitDeclarations(declarations);
if (globals()->empty()) return;
int array_index = 0;
Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
static_cast<int>(globals()->size()), TENURED);
for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
DeclareGlobalsNativeFlag::encode(info()->is_native()) |
DeclareGlobalsLanguageMode::encode(language_mode());
TemporaryRegisterScope temporary_register_scope(&builder_);
Register pairs = temporary_register_scope.NewRegister();
builder()->LoadLiteral(data);
builder()->StoreAccumulatorInRegister(pairs);
Register flags = temporary_register_scope.NewRegister();
builder()->LoadLiteral(Smi::FromInt(encoded_flags));
builder()->StoreAccumulatorInRegister(flags);
DCHECK(flags.index() == pairs.index() + 1);
builder()->CallRuntime(Runtime::kDeclareGlobals, pairs, 2);
globals()->clear();
}
void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Visit(stmt->expression()); Visit(stmt->expression());
} }
...@@ -391,11 +448,12 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -391,11 +448,12 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
VisitVariableLoad(proxy->var()); VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
} }
void BytecodeGenerator::VisitVariableLoad(Variable* variable) { void BytecodeGenerator::VisitVariableLoad(Variable* variable,
FeedbackVectorSlot slot) {
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::LOCAL: { case VariableLocation::LOCAL: {
Register source(variable->index()); Register source(variable->index());
...@@ -418,7 +476,66 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable) { ...@@ -418,7 +476,66 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable) {
builder()->LoadGlobal(variable->index()); builder()->LoadGlobal(variable->index());
break; break;
} }
case VariableLocation::UNALLOCATED: case VariableLocation::UNALLOCATED: {
TemporaryRegisterScope temporary_register_scope(&builder_);
Register obj = temporary_register_scope.NewRegister();
builder()->LoadContextSlot(current_context(),
Context::GLOBAL_OBJECT_INDEX);
builder()->StoreAccumulatorInRegister(obj);
builder()->LoadLiteral(variable->name());
builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode());
break;
}
case VariableLocation::CONTEXT:
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
}
}
void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
FeedbackVectorSlot slot) {
switch (variable->location()) {
case VariableLocation::LOCAL: {
// TODO(rmcilroy): support const mode initialization.
Register destination(variable->index());
builder()->StoreAccumulatorInRegister(destination);
break;
}
case VariableLocation::PARAMETER: {
// The parameter indices are shifted by 1 (receiver is variable
// index -1 but is parameter index 0 in BytecodeArrayBuilder).
Register destination(builder()->Parameter(variable->index() + 1));
builder()->StoreAccumulatorInRegister(destination);
break;
}
case VariableLocation::GLOBAL: {
// Global var, const, or let variable.
// TODO(rmcilroy): If context chain depth is short enough, do this using
// a generic version of LoadGlobalViaContextStub rather than calling the
// runtime.
DCHECK(variable->IsStaticGlobalObjectProperty());
builder()->StoreGlobal(variable->index(), language_mode());
break;
}
case VariableLocation::UNALLOCATED: {
TemporaryRegisterScope temporary_register_scope(&builder_);
Register value = temporary_register_scope.NewRegister();
Register obj = temporary_register_scope.NewRegister();
Register name = temporary_register_scope.NewRegister();
// TODO(rmcilroy): Investigate whether we can avoid having to stash the
// value in a register.
builder()->StoreAccumulatorInRegister(value);
builder()->LoadContextSlot(current_context(),
Context::GLOBAL_OBJECT_INDEX);
builder()->StoreAccumulatorInRegister(obj);
builder()->LoadLiteral(variable->name());
builder()->StoreAccumulatorInRegister(name);
builder()->LoadAccumulatorWithRegister(value);
builder()->StoreNamedProperty(obj, name, feedback_index(slot),
language_mode());
break;
}
case VariableLocation::CONTEXT: case VariableLocation::CONTEXT:
case VariableLocation::LOOKUP: case VariableLocation::LOOKUP:
UNIMPLEMENTED(); UNIMPLEMENTED();
...@@ -474,9 +591,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -474,9 +591,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
Variable* variable = expr->target()->AsVariableProxy()->var(); Variable* variable = expr->target()->AsVariableProxy()->var();
DCHECK(variable->location() == VariableLocation::LOCAL); VisitVariableAssignment(variable, slot);
Register destination(variable->index());
builder()->StoreAccumulatorInRegister(destination);
break; break;
} }
case NAMED_PROPERTY: case NAMED_PROPERTY:
...@@ -560,7 +675,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -560,7 +675,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
// Load callee as a global variable. // Load callee as a global variable.
VariableProxy* proxy = callee_expr->AsVariableProxy(); VariableProxy* proxy = callee_expr->AsVariableProxy();
VisitVariableLoad(proxy->var()); VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
builder()->StoreAccumulatorInRegister(callee); builder()->StoreAccumulatorInRegister(callee);
break; break;
} }
...@@ -741,6 +856,9 @@ int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { ...@@ -741,6 +856,9 @@ int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const {
return info()->feedback_vector()->GetIndex(slot); return info()->feedback_vector()->GetIndex(slot);
} }
Register BytecodeGenerator::current_context() const { return current_context_; }
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -24,6 +24,9 @@ class BytecodeGenerator : public AstVisitor { ...@@ -24,6 +24,9 @@ class BytecodeGenerator : public AstVisitor {
AST_NODE_LIST(DECLARE_VISIT) AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT #undef DECLARE_VISIT
// Visiting function for declarations list is overridden.
void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
private: private:
class ControlScope; class ControlScope;
class ControlScopeForIteration; class ControlScopeForIteration;
...@@ -32,7 +35,8 @@ class BytecodeGenerator : public AstVisitor { ...@@ -32,7 +35,8 @@ class BytecodeGenerator : public AstVisitor {
void VisitArithmeticExpression(BinaryOperation* binop); void VisitArithmeticExpression(BinaryOperation* binop);
void VisitPropertyLoad(Register obj, Property* expr); void VisitPropertyLoad(Register obj, Property* expr);
void VisitVariableLoad(Variable* variable); void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
// Dispatched from VisitUnaryOperation. // Dispatched from VisitUnaryOperation.
void VisitVoid(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr);
...@@ -46,15 +50,21 @@ class BytecodeGenerator : public AstVisitor { ...@@ -46,15 +50,21 @@ class BytecodeGenerator : public AstVisitor {
inline void set_control_scope(ControlScope* scope) { control_scope_ = scope; } inline void set_control_scope(ControlScope* scope) { control_scope_ = scope; }
inline CompilationInfo* info() const { return info_; } inline CompilationInfo* info() const { return info_; }
inline void set_info(CompilationInfo* info) { info_ = info; } inline void set_info(CompilationInfo* info) { info_ = info; }
ZoneVector<Handle<Object>>* globals() { return &globals_; }
LanguageMode language_mode() const; LanguageMode language_mode() const;
Strength language_mode_strength() const; Strength language_mode_strength() const;
int feedback_index(FeedbackVectorSlot slot) const; int feedback_index(FeedbackVectorSlot slot) const;
Register current_context() const;
BytecodeArrayBuilder builder_; BytecodeArrayBuilder builder_;
CompilationInfo* info_; CompilationInfo* info_;
Scope* scope_; Scope* scope_;
ZoneVector<Handle<Object>> globals_;
ControlScope* control_scope_; ControlScope* control_scope_;
// TODO(rmcilroy): Encapsulate this in an environment object.
Register current_context_;
}; };
} // namespace interpreter } // namespace interpreter
......
...@@ -266,6 +266,8 @@ std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) { ...@@ -266,6 +266,8 @@ std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) {
static const int kLastParamRegisterIndex = static const int kLastParamRegisterIndex =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
static const int kFunctionContextRegisterIndex =
-InterpreterFrameConstants::kContextFromRegisterPointer / kPointerSize;
// Registers occupy range 0-127 in 8-bit value leaving 128 unused values. // Registers occupy range 0-127 in 8-bit value leaving 128 unused values.
...@@ -291,6 +293,16 @@ int Register::ToParameterIndex(int parameter_count) const { ...@@ -291,6 +293,16 @@ int Register::ToParameterIndex(int parameter_count) const {
} }
Register Register::function_context() {
return Register(kFunctionContextRegisterIndex);
}
bool Register::is_function_context() const {
return index() == kFunctionContextRegisterIndex;
}
int Register::MaxParameterIndex() { return kMaxParameterIndex; } int Register::MaxParameterIndex() { return kMaxParameterIndex; }
......
...@@ -43,8 +43,12 @@ namespace interpreter { ...@@ -43,8 +43,12 @@ namespace interpreter {
V(LdaTrue, OperandType::kNone) \ V(LdaTrue, OperandType::kNone) \
V(LdaFalse, OperandType::kNone) \ V(LdaFalse, OperandType::kNone) \
\ \
/* Load globals */ \ /* Globals */ \
V(LdaGlobal, OperandType::kIdx8) \ V(LdaGlobal, OperandType::kIdx8) \
V(StaGlobal, OperandType::kIdx8) \
\
/* Context operations */ \
V(LdaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
\ \
/* Register-accumulator transfers */ \ /* Register-accumulator transfers */ \
V(Ldar, OperandType::kReg8) \ V(Ldar, OperandType::kReg8) \
...@@ -163,6 +167,10 @@ class Register { ...@@ -163,6 +167,10 @@ class Register {
int ToParameterIndex(int parameter_count) const; int ToParameterIndex(int parameter_count) const;
static int MaxParameterIndex(); static int MaxParameterIndex();
// Returns the register for the function's outer context.
static Register function_context();
bool is_function_context() const;
static Register FromOperand(uint8_t operand); static Register FromOperand(uint8_t operand);
uint8_t ToOperand() const; uint8_t ToOperand() const;
......
...@@ -196,6 +196,31 @@ void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) { ...@@ -196,6 +196,31 @@ void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) {
} }
// StaGlobal <slot_index>
//
// Store the global at |slot_index| with the value in the the accumulator.
void Interpreter::DoStaGlobal(compiler::InterpreterAssembler* assembler) {
Node* slot_index = __ BytecodeOperandIdx8(0);
Node* smi_slot_index = __ SmiTag(slot_index);
Node* value = __ GetAccumulator();
__ CallRuntime(Runtime::kStoreGlobalViaContext_Sloppy, smi_slot_index, value);
__ Dispatch();
}
// LdaContextSlot <context> <slot_index>
//
// Load the object in |slot_index| of |context| into the accumulator.
void Interpreter::DoLdaContextSlot(compiler::InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg8(0);
Node* context = __ LoadRegister(reg_index);
Node* slot_index = __ BytecodeOperandIdx8(1);
Node* result = __ LoadContextSlot(context, slot_index);
__ SetAccumulator(result);
__ Dispatch();
}
void Interpreter::DoPropertyLoadIC(Callable ic, void Interpreter::DoPropertyLoadIC(Callable ic,
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code()); Node* code_target = __ HeapConstant(ic.code());
......
...@@ -555,6 +555,27 @@ TEST(InterpreterParameter8) { ...@@ -555,6 +555,27 @@ TEST(InterpreterParameter8) {
} }
TEST(InterpreterParameter1Assign) {
HandleAndZoneScope handles;
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(0);
builder.set_parameter_count(1);
builder.LoadLiteral(Smi::FromInt(5))
.StoreAccumulatorInRegister(builder.Parameter(0))
.LoadAccumulatorWithRegister(builder.Parameter(0))
.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
auto callable = tester.GetCallable<Handle<Object>>();
Handle<Object> return_val =
callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
.ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
}
TEST(InterpreterLoadGlobal) { TEST(InterpreterLoadGlobal) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
...@@ -572,6 +593,28 @@ TEST(InterpreterLoadGlobal) { ...@@ -572,6 +593,28 @@ TEST(InterpreterLoadGlobal) {
} }
TEST(InterpreterStoreGlobal) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
// Test storing to a global.
std::string source(
"var global = 321;\n"
"function " + InterpreterTester::function_name() + "() {\n"
" global = 999;\n"
"}");
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
callable().ToHandleChecked();
Handle<i::String> name = factory->InternalizeUtf8String("global");
Handle<i::Object> global_obj =
Object::GetProperty(isolate->global_object(), name).ToHandleChecked();
CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
}
TEST(InterpreterCallGlobal) { TEST(InterpreterCallGlobal) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
...@@ -589,6 +632,45 @@ TEST(InterpreterCallGlobal) { ...@@ -589,6 +632,45 @@ TEST(InterpreterCallGlobal) {
} }
TEST(InterpreterLoadUnallocated) {
HandleAndZoneScope handles;
// Test loading an unallocated global.
std::string source(
"unallocated = 123;\n"
"function " + InterpreterTester::function_name() + "() {\n"
" return unallocated;\n"
"}");
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
}
TEST(InterpreterStoreUnallocated) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
// Test storing to an unallocated global.
std::string source(
"unallocated = 321;\n"
"function " + InterpreterTester::function_name() + "() {\n"
" unallocated = 999;\n"
"}");
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
callable().ToHandleChecked();
Handle<i::String> name = factory->InternalizeUtf8String("unallocated");
Handle<i::Object> global_obj =
Object::GetProperty(isolate->global_object(), name).ToHandleChecked();
CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
}
TEST(InterpreterLoadNamedProperty) { TEST(InterpreterLoadNamedProperty) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate(); i::Isolate* isolate = handles.main_isolate();
......
...@@ -474,18 +474,14 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { ...@@ -474,18 +474,14 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) {
TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode); InterpreterAssemblerForTest m(this, bytecode);
Node* load_from_current_context = m.LoadContextSlot(22); Node* context = m.Int32Constant(1);
Matcher<Node*> load_from_current_context_matcher = m.IsLoad( Node* slot_index = m.Int32Constant(22);
kMachAnyTagged, IsParameter(Linkage::kInterpreterContextParameter), Node* load_context_slot = m.LoadContextSlot(context, slot_index);
IsIntPtrConstant(Context::SlotOffset(22)));
EXPECT_THAT(load_from_current_context, load_from_current_context_matcher); Matcher<Node*> offset =
IsIntPtrAdd(IsWordShl(slot_index, IsInt32Constant(kPointerSizeLog2)),
// Let's imagine that the loaded context slot is another context. IsInt32Constant(Context::kHeaderSize - kHeapObjectTag));
Node* load_from_any_context = EXPECT_THAT(load_context_slot, m.IsLoad(kMachAnyTagged, context, offset));
m.LoadContextSlot(load_from_current_context, 23);
EXPECT_THAT(load_from_any_context,
m.IsLoad(kMachAnyTagged, load_from_current_context_matcher,
IsIntPtrConstant(Context::SlotOffset(23))));
} }
} }
......
...@@ -40,8 +40,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -40,8 +40,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
Register reg(0); Register reg(0);
builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg); builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg);
// Emit global load operations. // Emit global load / store operations.
builder.LoadGlobal(1); builder.LoadGlobal(1);
builder.StoreGlobal(1, LanguageMode::SLOPPY);
// Emit context load operations.
builder.LoadContextSlot(reg, 1);
// Emit load / store property operations. // Emit load / store property operations.
builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY) builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY)
......
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