Commit 8087c49d authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add support for loading globals in the interpreter.

Adds LdaGlobal bytecode and augments BytecodeGenerator to load globals for
global variables and function calls.

Modified TestBytecodeGenerator to add the ability to specify that a bytecode
operand has an unknown value (used so we don't need to figure out the slot
index of a global). Also added a helper which checks equality of BytecodeArray
with the expected snipptets.

Modified TestInterpreter to allow it to take snippets of JS and have the
BytecodeGenerator generate the bytecode rather than having to build a
BytecodeArray manually. This is used to enable the global tests.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30910}
parent 809f6b15
......@@ -249,6 +249,12 @@ void BytecodeGraphBuilder::VisitStar(
}
void BytecodeGraphBuilder::VisitLdaGlobal(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLoadIC(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
......
......@@ -315,6 +315,13 @@ Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
}
Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
Node* arg1) {
return raw_assembler_->CallRuntime1(function_id, arg1,
ContextTaggedPointer());
}
Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
Node* arg1, Node* arg2) {
return raw_assembler_->CallRuntime2(function_id, arg1, arg2,
......
......@@ -104,6 +104,7 @@ class InterpreterAssembler {
Node* arg2, Node* arg3, Node* arg4, Node* arg5);
// Call runtime function.
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1, Node* arg2);
// Returns from the function.
......
......@@ -152,6 +152,16 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int slot_index) {
DCHECK(slot_index >= 0);
if (FitsInByteOperand(slot_index)) {
Output(Bytecode::kLdaGlobal, static_cast<uint8_t>(slot_index));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
Register object, int feedback_slot, LanguageMode language_mode) {
if (!is_sloppy(language_mode)) {
......
......@@ -49,6 +49,9 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& LoadTrue();
BytecodeArrayBuilder& LoadFalse();
// Global loads to accumulator.
BytecodeArrayBuilder& LoadGlobal(int slot_index);
// Register-accumulator transfers.
BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
......
......@@ -32,7 +32,7 @@ Bytecode BytecodeArrayIterator::current_bytecode() const {
}
uint8_t BytecodeArrayIterator::GetOperand(int operand_index,
uint8_t BytecodeArrayIterator::GetRawOperand(int operand_index,
OperandType operand_type) const {
DCHECK_GE(operand_index, 0);
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
......@@ -44,19 +44,19 @@ uint8_t BytecodeArrayIterator::GetOperand(int operand_index,
int8_t BytecodeArrayIterator::GetSmi8Operand(int operand_index) const {
uint8_t operand = GetOperand(operand_index, OperandType::kImm8);
uint8_t operand = GetRawOperand(operand_index, OperandType::kImm8);
return static_cast<int8_t>(operand);
}
int BytecodeArrayIterator::GetIndexOperand(int operand_index) const {
uint8_t operand = GetOperand(operand_index, OperandType::kIdx);
uint8_t operand = GetRawOperand(operand_index, OperandType::kIdx);
return static_cast<int>(operand);
}
Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
uint8_t operand = GetOperand(operand_index, OperandType::kReg);
uint8_t operand = GetRawOperand(operand_index, OperandType::kReg);
return Register::FromOperand(operand);
}
......
......@@ -29,9 +29,11 @@ class BytecodeArrayIterator {
Register GetRegisterOperand(int operand_index) const;
Handle<Object> GetConstantForIndexOperand(int operand_index) const;
private:
uint8_t GetOperand(int operand_index, OperandType operand_type) const;
// Get the raw byte for the given operand. Note: you should prefer using the
// typed versions above which cast the return to an appropriate type.
uint8_t GetRawOperand(int operand_index, OperandType operand_type) const;
private:
Handle<BytecodeArray> bytecode_array_;
int bytecode_offset_;
......
......@@ -251,7 +251,11 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
Variable* variable = proxy->var();
VisitVariableLoad(proxy->var());
}
void BytecodeGenerator::VisitVariableLoad(Variable* variable) {
switch (variable->location()) {
case VariableLocation::LOCAL: {
Register source(variable->index());
......@@ -265,7 +269,15 @@ void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
builder().LoadAccumulatorWithRegister(source);
break;
}
case VariableLocation::GLOBAL:
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().LoadGlobal(variable->index());
break;
}
case VariableLocation::UNALLOCATED:
case VariableLocation::CONTEXT:
case VariableLocation::LOOKUP:
......@@ -403,7 +415,15 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder().StoreAccumulatorInRegister(callee);
break;
}
case Call::GLOBAL_CALL:
case Call::GLOBAL_CALL: {
// Receiver is undefined for global calls.
builder().LoadUndefined().StoreAccumulatorInRegister(receiver);
// Load callee as a global variable.
VariableProxy* proxy = callee_expr->AsVariableProxy();
VisitVariableLoad(proxy->var());
builder().StoreAccumulatorInRegister(callee);
break;
}
case Call::LOOKUP_SLOT_CALL:
case Call::SUPER_CALL:
case Call::POSSIBLY_EVAL_CALL:
......
......@@ -29,6 +29,7 @@ class BytecodeGenerator : public AstVisitor {
void VisitArithmeticExpression(BinaryOperation* binop);
void VisitPropertyLoad(Register obj, Property* expr);
void VisitVariableLoad(Variable* variable);
inline BytecodeArrayBuilder& builder() { return builder_; }
inline Scope* scope() const { return scope_; }
......
......@@ -36,6 +36,9 @@ namespace interpreter {
V(LdaTrue, OperandType::kNone) \
V(LdaFalse, OperandType::kNone) \
\
/* Load globals */ \
V(LdaGlobal, OperandType::kIdx) \
\
/* Register-accumulator transfers */ \
V(Ldar, OperandType::kReg) \
V(Star, OperandType::kReg) \
......
......@@ -191,6 +191,18 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
}
// LdaGlobal <slot_index>
//
// Load the global at |slot_index| into the accumulator.
void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) {
Node* slot_index = __ BytecodeOperandIdx(0);
Node* smi_slot_index = __ SmiTag(slot_index);
Node* result = __ CallRuntime(Runtime::kLoadGlobalViaContext, smi_slot_index);
__ SetAccumulator(result);
__ Dispatch();
}
void Interpreter::DoPropertyLoadIC(Callable ic,
compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code());
......
This diff is collapsed.
......@@ -39,6 +39,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
Register reg(0);
builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg);
// Emit global load operations.
builder.LoadGlobal(1);
// Emit load / store property operations.
builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY)
.LoadKeyedProperty(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