Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
| 6 | 6 |
| 7 #include <stack> | 7 #include <stack> |
| 8 | 8 |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/objects.h" | 10 #include "src/objects.h" |
| 11 #include "src/scopes.h" | 11 #include "src/scopes.h" |
| 12 #include "src/token.h" | 12 #include "src/token.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 namespace interpreter { | 16 namespace interpreter { |
| 17 | 17 |
| 18 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) | 18 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
| 19 : builder_(isolate, zone) { | 19 : builder_(isolate, zone), |
| 20 globals_(0, zone), | |
| 21 current_context_(Register::function_context()) { | |
| 20 InitializeAstVisitor(isolate, zone); | 22 InitializeAstVisitor(isolate, zone); |
| 21 } | 23 } |
| 22 | 24 |
| 23 | 25 |
| 24 BytecodeGenerator::~BytecodeGenerator() {} | 26 BytecodeGenerator::~BytecodeGenerator() {} |
| 25 | 27 |
| 26 | 28 |
| 27 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { | 29 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
| 28 set_info(info); | 30 set_info(info); |
| 29 set_scope(info->scope()); | 31 set_scope(info->scope()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 VisitDeclarations(node->scope()->declarations()); | 63 VisitDeclarations(node->scope()->declarations()); |
| 62 VisitStatements(node->statements()); | 64 VisitStatements(node->statements()); |
| 63 } | 65 } |
| 64 } | 66 } |
| 65 builder().LeaveBlock(); | 67 builder().LeaveBlock(); |
| 66 } | 68 } |
| 67 | 69 |
| 68 | 70 |
| 69 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { | 71 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { |
| 70 Variable* variable = decl->proxy()->var(); | 72 Variable* variable = decl->proxy()->var(); |
| 73 VariableMode mode = decl->mode(); | |
| 74 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; | |
| 75 DCHECK(!hole_init); // TODO(rmcilroy): Implement hole_init support. | |
|
oth
2015/10/01 12:02:26
if (!hole_init) UNIMPLEMENTED().
rmcilroy
2015/10/06 14:10:26
Done.
| |
| 71 switch (variable->location()) { | 76 switch (variable->location()) { |
| 72 case VariableLocation::GLOBAL: | 77 case VariableLocation::GLOBAL: |
| 73 case VariableLocation::UNALLOCATED: | 78 case VariableLocation::UNALLOCATED: { |
| 74 UNIMPLEMENTED(); | 79 Handle<Oddball> value = variable->binding_needs_init() |
| 80 ? isolate()->factory()->the_hole_value() | |
| 81 : isolate()->factory()->undefined_value(); | |
| 82 globals()->push_back(variable->name()); | |
| 83 globals()->push_back(value); | |
| 75 break; | 84 break; |
| 85 } | |
| 76 case VariableLocation::PARAMETER: | 86 case VariableLocation::PARAMETER: |
| 77 case VariableLocation::LOCAL: | 87 case VariableLocation::LOCAL: |
| 78 // Details stored in scope, i.e. variable index. | 88 // Details stored in scope, i.e. variable index. |
| 79 break; | 89 break; |
| 80 case VariableLocation::CONTEXT: | 90 case VariableLocation::CONTEXT: |
| 81 case VariableLocation::LOOKUP: | 91 case VariableLocation::LOOKUP: |
| 82 UNIMPLEMENTED(); | 92 UNIMPLEMENTED(); |
| 83 break; | 93 break; |
| 84 } | 94 } |
| 85 } | 95 } |
| 86 | 96 |
| 87 | 97 |
| 88 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { | 98 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
| 89 UNIMPLEMENTED(); | 99 Variable* variable = decl->proxy()->var(); |
| 100 switch (variable->location()) { | |
| 101 case VariableLocation::GLOBAL: | |
| 102 case VariableLocation::UNALLOCATED: { | |
| 103 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo( | |
| 104 decl->fun(), info()->script(), info()); | |
| 105 // Check for stack-overflow exception. | |
| 106 if (function.is_null()) return SetStackOverflow(); | |
| 107 globals()->push_back(variable->name()); | |
| 108 globals()->push_back(function); | |
| 109 break; | |
| 110 } | |
| 111 case VariableLocation::PARAMETER: | |
| 112 case VariableLocation::LOCAL: | |
| 113 case VariableLocation::CONTEXT: | |
| 114 case VariableLocation::LOOKUP: | |
| 115 UNIMPLEMENTED(); | |
| 116 } | |
| 90 } | 117 } |
| 91 | 118 |
| 92 | 119 |
| 93 void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) { | 120 void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) { |
| 94 UNIMPLEMENTED(); | 121 UNIMPLEMENTED(); |
| 95 } | 122 } |
| 96 | 123 |
| 97 | 124 |
| 98 void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) { | 125 void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) { |
| 99 UNIMPLEMENTED(); | 126 UNIMPLEMENTED(); |
| 100 } | 127 } |
| 101 | 128 |
| 102 | 129 |
| 130 void BytecodeGenerator::VisitDeclarations( | |
| 131 ZoneList<Declaration*>* declarations) { | |
| 132 DCHECK(globals()->empty()); | |
| 133 AstVisitor::VisitDeclarations(declarations); | |
| 134 if (globals()->empty()) return; | |
| 135 int array_index = 0; | |
| 136 Handle<FixedArray> data = isolate()->factory()->NewFixedArray( | |
| 137 static_cast<int>(globals()->size()), TENURED); | |
| 138 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj); | |
| 139 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) | | |
| 140 DeclareGlobalsNativeFlag::encode(info()->is_native()) | | |
| 141 DeclareGlobalsLanguageMode::encode(language_mode()); | |
| 142 | |
| 143 TemporaryRegisterScope temporary_register_scope(&builder_); | |
| 144 Register pairs = temporary_register_scope.NewRegister(); | |
| 145 builder().LoadLiteral(data); | |
| 146 builder().StoreAccumulatorInRegister(pairs); | |
| 147 | |
| 148 Register flags = temporary_register_scope.NewRegister(); | |
| 149 builder().LoadLiteral(Smi::FromInt(encoded_flags)); | |
| 150 builder().StoreAccumulatorInRegister(flags); | |
| 151 DCHECK(flags.index() == pairs.index() + 1); | |
| 152 | |
| 153 builder().CallRuntime(Runtime::kDeclareGlobals, pairs, 2); | |
| 154 globals()->clear(); | |
| 155 } | |
| 156 | |
| 157 | |
| 103 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | 158 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 104 Visit(stmt->expression()); | 159 Visit(stmt->expression()); |
| 105 } | 160 } |
| 106 | 161 |
| 107 | 162 |
| 108 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { | 163 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
| 109 // TODO(oth): For control-flow it could be useful to signal empty paths here. | 164 // TODO(oth): For control-flow it could be useful to signal empty paths here. |
| 110 } | 165 } |
| 111 | 166 |
| 112 | 167 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 UNIMPLEMENTED(); | 306 UNIMPLEMENTED(); |
| 252 } | 307 } |
| 253 | 308 |
| 254 | 309 |
| 255 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 310 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 256 UNIMPLEMENTED(); | 311 UNIMPLEMENTED(); |
| 257 } | 312 } |
| 258 | 313 |
| 259 | 314 |
| 260 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { | 315 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { |
| 261 VisitVariableLoad(proxy->var()); | 316 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
| 262 } | 317 } |
| 263 | 318 |
| 264 | 319 |
| 265 void BytecodeGenerator::VisitVariableLoad(Variable* variable) { | 320 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
| 321 FeedbackVectorICSlot slot) { | |
| 266 switch (variable->location()) { | 322 switch (variable->location()) { |
| 267 case VariableLocation::LOCAL: { | 323 case VariableLocation::LOCAL: { |
| 268 Register source(variable->index()); | 324 Register source(variable->index()); |
| 269 builder().LoadAccumulatorWithRegister(source); | 325 builder().LoadAccumulatorWithRegister(source); |
| 270 break; | 326 break; |
| 271 } | 327 } |
| 272 case VariableLocation::PARAMETER: { | 328 case VariableLocation::PARAMETER: { |
| 273 // The parameter indices are shifted by 1 (receiver is variable | 329 // The parameter indices are shifted by 1 (receiver is variable |
| 274 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 330 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 275 Register source(builder().Parameter(variable->index() + 1)); | 331 Register source(builder().Parameter(variable->index() + 1)); |
| 276 builder().LoadAccumulatorWithRegister(source); | 332 builder().LoadAccumulatorWithRegister(source); |
| 277 break; | 333 break; |
| 278 } | 334 } |
| 279 case VariableLocation::GLOBAL: { | 335 case VariableLocation::GLOBAL: { |
| 280 // Global var, const, or let variable. | 336 // Global var, const, or let variable. |
| 281 // TODO(rmcilroy): If context chain depth is short enough, do this using | 337 // TODO(rmcilroy): If context chain depth is short enough, do this using |
| 282 // a generic version of LoadGlobalViaContextStub rather than calling the | 338 // a generic version of LoadGlobalViaContextStub rather than calling the |
| 283 // runtime. | 339 // runtime. |
| 284 DCHECK(variable->IsStaticGlobalObjectProperty()); | 340 DCHECK(variable->IsStaticGlobalObjectProperty()); |
| 285 builder().LoadGlobal(variable->index()); | 341 builder().LoadGlobal(variable->index()); |
| 286 break; | 342 break; |
| 287 } | 343 } |
| 288 case VariableLocation::UNALLOCATED: | 344 case VariableLocation::UNALLOCATED: { |
| 345 TemporaryRegisterScope temporary_register_scope(&builder_); | |
| 346 Register obj = temporary_register_scope.NewRegister(); | |
| 347 builder().LoadContextSlot(current_context(), | |
| 348 Context::GLOBAL_OBJECT_INDEX); | |
| 349 builder().StoreAccumulatorInRegister(obj); | |
| 350 builder().LoadLiteral(variable->name()); | |
| 351 builder().LoadNamedProperty(obj, feedback_index(slot), language_mode()); | |
| 352 break; | |
| 353 } | |
| 289 case VariableLocation::CONTEXT: | 354 case VariableLocation::CONTEXT: |
| 290 case VariableLocation::LOOKUP: | 355 case VariableLocation::LOOKUP: |
| 291 UNIMPLEMENTED(); | 356 UNIMPLEMENTED(); |
| 357 } | |
| 358 } | |
| 359 | |
| 360 | |
| 361 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | |
| 362 FeedbackVectorICSlot slot) { | |
| 363 switch (variable->location()) { | |
| 364 case VariableLocation::LOCAL: { | |
| 365 // TODO(rmcilroy): support const mode initialization. | |
| 366 Register destination(variable->index()); | |
| 367 builder().StoreAccumulatorInRegister(destination); | |
| 368 break; | |
| 369 } | |
| 370 case VariableLocation::PARAMETER: { | |
| 371 // The parameter indices are shifted by 1 (receiver is variable | |
| 372 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | |
| 373 Register destination(builder().Parameter(variable->index() + 1)); | |
| 374 builder().StoreAccumulatorInRegister(destination); | |
| 375 break; | |
| 376 } | |
| 377 case VariableLocation::GLOBAL: { | |
| 378 // Global var, const, or let variable. | |
| 379 // TODO(rmcilroy): If context chain depth is short enough, do this using | |
| 380 // a generic version of LoadGlobalViaContextStub rather than calling the | |
| 381 // runtime. | |
| 382 DCHECK(variable->IsStaticGlobalObjectProperty()); | |
| 383 builder().StoreGlobal(variable->index(), language_mode()); | |
| 384 break; | |
| 385 } | |
| 386 case VariableLocation::UNALLOCATED: { | |
| 387 TemporaryRegisterScope temporary_register_scope(&builder_); | |
| 388 Register value = temporary_register_scope.NewRegister(); | |
| 389 Register obj = temporary_register_scope.NewRegister(); | |
| 390 Register name = temporary_register_scope.NewRegister(); | |
| 391 // TODO(rmcilroy): Investigate whether we can avoid having to stash the | |
| 392 // value in a register. | |
| 393 builder().StoreAccumulatorInRegister(value); | |
| 394 builder().LoadContextSlot(current_context(), | |
| 395 Context::GLOBAL_OBJECT_INDEX); | |
| 396 builder().StoreAccumulatorInRegister(obj); | |
| 397 builder().LoadLiteral(variable->name()); | |
| 398 builder().StoreAccumulatorInRegister(name); | |
| 399 builder().LoadAccumulatorWithRegister(value); | |
| 400 builder().StoreNamedProperty(obj, name, feedback_index(slot), | |
| 401 language_mode()); | |
| 402 break; | |
| 403 } | |
| 404 case VariableLocation::CONTEXT: | |
| 405 case VariableLocation::LOOKUP: | |
| 406 UNIMPLEMENTED(); | |
| 292 } | 407 } |
| 293 } | 408 } |
| 294 | 409 |
| 295 | 410 |
| 296 void BytecodeGenerator::VisitAssignment(Assignment* expr) { | 411 void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
| 297 DCHECK(expr->target()->IsValidReferenceExpression()); | 412 DCHECK(expr->target()->IsValidReferenceExpression()); |
| 298 TemporaryRegisterScope temporary_register_scope(&builder_); | 413 TemporaryRegisterScope temporary_register_scope(&builder_); |
| 299 Register object, key; | 414 Register object, key; |
| 300 | 415 |
| 301 // Left-hand side can only be a property, a global or a variable slot. | 416 // Left-hand side can only be a property, a global or a variable slot. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 UNIMPLEMENTED(); | 449 UNIMPLEMENTED(); |
| 335 } else { | 450 } else { |
| 336 Visit(expr->value()); | 451 Visit(expr->value()); |
| 337 } | 452 } |
| 338 | 453 |
| 339 // Store the value. | 454 // Store the value. |
| 340 FeedbackVectorICSlot slot = expr->AssignmentSlot(); | 455 FeedbackVectorICSlot slot = expr->AssignmentSlot(); |
| 341 switch (assign_type) { | 456 switch (assign_type) { |
| 342 case VARIABLE: { | 457 case VARIABLE: { |
| 343 Variable* variable = expr->target()->AsVariableProxy()->var(); | 458 Variable* variable = expr->target()->AsVariableProxy()->var(); |
| 344 DCHECK(variable->location() == VariableLocation::LOCAL); | 459 VisitVariableAssignment(variable, slot); |
| 345 Register destination(variable->index()); | |
| 346 builder().StoreAccumulatorInRegister(destination); | |
| 347 break; | 460 break; |
| 348 } | 461 } |
| 349 case NAMED_PROPERTY: | 462 case NAMED_PROPERTY: |
| 350 builder().StoreNamedProperty(object, key, feedback_index(slot), | 463 builder().StoreNamedProperty(object, key, feedback_index(slot), |
| 351 language_mode()); | 464 language_mode()); |
| 352 break; | 465 break; |
| 353 case KEYED_PROPERTY: | 466 case KEYED_PROPERTY: |
| 354 builder().StoreKeyedProperty(object, key, feedback_index(slot), | 467 builder().StoreKeyedProperty(object, key, feedback_index(slot), |
| 355 language_mode()); | 468 language_mode()); |
| 356 break; | 469 break; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 // Perform a property load of the callee. | 533 // Perform a property load of the callee. |
| 421 VisitPropertyLoad(receiver, property); | 534 VisitPropertyLoad(receiver, property); |
| 422 builder().StoreAccumulatorInRegister(callee); | 535 builder().StoreAccumulatorInRegister(callee); |
| 423 break; | 536 break; |
| 424 } | 537 } |
| 425 case Call::GLOBAL_CALL: { | 538 case Call::GLOBAL_CALL: { |
| 426 // Receiver is undefined for global calls. | 539 // Receiver is undefined for global calls. |
| 427 builder().LoadUndefined().StoreAccumulatorInRegister(receiver); | 540 builder().LoadUndefined().StoreAccumulatorInRegister(receiver); |
| 428 // Load callee as a global variable. | 541 // Load callee as a global variable. |
| 429 VariableProxy* proxy = callee_expr->AsVariableProxy(); | 542 VariableProxy* proxy = callee_expr->AsVariableProxy(); |
| 430 VisitVariableLoad(proxy->var()); | 543 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
| 431 builder().StoreAccumulatorInRegister(callee); | 544 builder().StoreAccumulatorInRegister(callee); |
| 432 break; | 545 break; |
| 433 } | 546 } |
| 434 case Call::LOOKUP_SLOT_CALL: | 547 case Call::LOOKUP_SLOT_CALL: |
| 435 case Call::SUPER_CALL: | 548 case Call::SUPER_CALL: |
| 436 case Call::POSSIBLY_EVAL_CALL: | 549 case Call::POSSIBLY_EVAL_CALL: |
| 437 case Call::OTHER_CALL: | 550 case Call::OTHER_CALL: |
| 438 UNIMPLEMENTED(); | 551 UNIMPLEMENTED(); |
| 439 } | 552 } |
| 440 | 553 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 563 | 676 |
| 564 LanguageMode BytecodeGenerator::language_mode() const { | 677 LanguageMode BytecodeGenerator::language_mode() const { |
| 565 return info()->language_mode(); | 678 return info()->language_mode(); |
| 566 } | 679 } |
| 567 | 680 |
| 568 | 681 |
| 569 int BytecodeGenerator::feedback_index(FeedbackVectorICSlot slot) const { | 682 int BytecodeGenerator::feedback_index(FeedbackVectorICSlot slot) const { |
| 570 return info()->feedback_vector()->GetIndex(slot); | 683 return info()->feedback_vector()->GetIndex(slot); |
| 571 } | 684 } |
| 572 | 685 |
| 686 | |
| 687 Register BytecodeGenerator::current_context() const { return current_context_; } | |
| 688 | |
| 573 } // namespace interpreter | 689 } // namespace interpreter |
| 574 } // namespace internal | 690 } // namespace internal |
| 575 } // namespace v8 | 691 } // namespace v8 |
| OLD | NEW |