Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index 9fd03fd016ea4d1417d971f5469700941c0f157d..423c438cf2c17910227d08fd4b873294538d2dbb 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -93,7 +93,9 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
: builder_(isolate, zone), |
info_(nullptr), |
scope_(nullptr), |
- control_scope_(nullptr) { |
+ globals_(0, zone), |
+ control_scope_(nullptr), |
+ current_context_(Register::function_context()) { |
InitializeAstVisitor(isolate, zone); |
} |
@@ -145,11 +147,21 @@ void BytecodeGenerator::VisitBlock(Block* node) { |
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { |
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()) { |
case VariableLocation::GLOBAL: |
- case VariableLocation::UNALLOCATED: |
- UNIMPLEMENTED(); |
+ case VariableLocation::UNALLOCATED: { |
+ 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; |
+ } |
case VariableLocation::PARAMETER: |
case VariableLocation::LOCAL: |
// Details stored in scope, i.e. variable index. |
@@ -163,7 +175,24 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* 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) { |
} |
+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) { |
Visit(stmt->expression()); |
} |
@@ -391,11 +448,12 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
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()) { |
case VariableLocation::LOCAL: { |
Register source(variable->index()); |
@@ -418,7 +476,66 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable) { |
builder()->LoadGlobal(variable->index()); |
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::LOOKUP: |
UNIMPLEMENTED(); |
@@ -474,9 +591,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
switch (assign_type) { |
case VARIABLE: { |
Variable* variable = expr->target()->AsVariableProxy()->var(); |
- DCHECK(variable->location() == VariableLocation::LOCAL); |
- Register destination(variable->index()); |
- builder()->StoreAccumulatorInRegister(destination); |
+ VisitVariableAssignment(variable, slot); |
break; |
} |
case NAMED_PROPERTY: |
@@ -560,7 +675,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); |
// Load callee as a global variable. |
VariableProxy* proxy = callee_expr->AsVariableProxy(); |
- VisitVariableLoad(proxy->var()); |
+ VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
builder()->StoreAccumulatorInRegister(callee); |
break; |
} |
@@ -741,6 +856,9 @@ int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
return info()->feedback_vector()->GetIndex(slot); |
} |
+ |
+Register BytecodeGenerator::current_context() const { return current_context_; } |
+ |
} // namespace interpreter |
} // namespace internal |
} // namespace v8 |