| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 // Return is breakable if the expression is. | 89 // Return is breakable if the expression is. |
| 90 Visit(stmt->expression()); | 90 Visit(stmt->expression()); |
| 91 } | 91 } |
| 92 | 92 |
| 93 | 93 |
| 94 void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) { | 94 void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) { |
| 95 Visit(stmt->expression()); | 95 Visit(stmt->expression()); |
| 96 } | 96 } |
| 97 | 97 |
| 98 | 98 |
| 99 void BreakableStatementChecker::VisitExitContextStatement( | |
| 100 ExitContextStatement* stmt) { | |
| 101 } | |
| 102 | |
| 103 | |
| 104 void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) { | 99 void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) { |
| 105 // Switch statements breakable if the tag expression is. | 100 // Switch statements breakable if the tag expression is. |
| 106 Visit(stmt->tag()); | 101 Visit(stmt->tag()); |
| 107 } | 102 } |
| 108 | 103 |
| 109 | 104 |
| 110 void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { | 105 void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 111 // Mark do while as breakable to avoid adding a break slot in front of it. | 106 // Mark do while as breakable to avoid adding a break slot in front of it. |
| 112 is_breakable_ = true; | 107 is_breakable_ = true; |
| 113 } | 108 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 } | 178 } |
| 184 | 179 |
| 185 | 180 |
| 186 void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) { | 181 void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) { |
| 187 } | 182 } |
| 188 | 183 |
| 189 | 184 |
| 190 void BreakableStatementChecker::VisitAssignment(Assignment* expr) { | 185 void BreakableStatementChecker::VisitAssignment(Assignment* expr) { |
| 191 // If assigning to a property (including a global property) the assignment is | 186 // If assigning to a property (including a global property) the assignment is |
| 192 // breakable. | 187 // breakable. |
| 193 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 188 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
| 194 Property* prop = expr->target()->AsProperty(); | 189 Property* prop = expr->target()->AsProperty(); |
| 195 if (prop != NULL || (var != NULL && var->is_global())) { | 190 if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) { |
| 196 is_breakable_ = true; | 191 is_breakable_ = true; |
| 197 return; | 192 return; |
| 198 } | 193 } |
| 199 | 194 |
| 200 // Otherwise the assignment is breakable if the assigned value is. | 195 // Otherwise the assignment is breakable if the assigned value is. |
| 201 Visit(expr->value()); | 196 Visit(expr->value()); |
| 202 } | 197 } |
| 203 | 198 |
| 204 | 199 |
| 205 void BreakableStatementChecker::VisitThrow(Throw* expr) { | 200 void BreakableStatementChecker::VisitThrow(Throw* expr) { |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 | 383 |
| 389 | 384 |
| 390 void FullCodeGenerator::RecordStackCheck(int ast_id) { | 385 void FullCodeGenerator::RecordStackCheck(int ast_id) { |
| 391 // The pc offset does not need to be encoded and packed together with a | 386 // The pc offset does not need to be encoded and packed together with a |
| 392 // state. | 387 // state. |
| 393 BailoutEntry entry = { ast_id, masm_->pc_offset() }; | 388 BailoutEntry entry = { ast_id, masm_->pc_offset() }; |
| 394 stack_checks_.Add(entry); | 389 stack_checks_.Add(entry); |
| 395 } | 390 } |
| 396 | 391 |
| 397 | 392 |
| 398 int FullCodeGenerator::SlotOffset(Slot* slot) { | |
| 399 ASSERT(slot != NULL); | |
| 400 // Offset is negative because higher indexes are at lower addresses. | |
| 401 int offset = -slot->index() * kPointerSize; | |
| 402 // Adjust by a (parameter or local) base offset. | |
| 403 switch (slot->type()) { | |
| 404 case Slot::PARAMETER: | |
| 405 offset += (info_->scope()->num_parameters() + 1) * kPointerSize; | |
| 406 break; | |
| 407 case Slot::LOCAL: | |
| 408 offset += JavaScriptFrameConstants::kLocal0Offset; | |
| 409 break; | |
| 410 case Slot::CONTEXT: | |
| 411 case Slot::LOOKUP: | |
| 412 UNREACHABLE(); | |
| 413 } | |
| 414 return offset; | |
| 415 } | |
| 416 | |
| 417 | |
| 418 bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) { | 393 bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) { |
| 419 // Inline smi case inside loops, but not division and modulo which | 394 // Inline smi case inside loops, but not division and modulo which |
| 420 // are too complicated and take up too much space. | 395 // are too complicated and take up too much space. |
| 421 if (op == Token::DIV ||op == Token::MOD) return false; | 396 if (op == Token::DIV ||op == Token::MOD) return false; |
| 422 if (FLAG_always_inline_smi_code) return true; | 397 if (FLAG_always_inline_smi_code) return true; |
| 423 return loop_depth_ > 0; | 398 return loop_depth_ > 0; |
| 424 } | 399 } |
| 425 | 400 |
| 426 | 401 |
| 427 void FullCodeGenerator::EffectContext::Plug(Register reg) const { | 402 void FullCodeGenerator::EffectContext::Plug(Register reg) const { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 DoTest(context->condition(), | 497 DoTest(context->condition(), |
| 523 context->true_label(), | 498 context->true_label(), |
| 524 context->false_label(), | 499 context->false_label(), |
| 525 context->fall_through()); | 500 context->fall_through()); |
| 526 } | 501 } |
| 527 | 502 |
| 528 | 503 |
| 529 void FullCodeGenerator::VisitDeclarations( | 504 void FullCodeGenerator::VisitDeclarations( |
| 530 ZoneList<Declaration*>* declarations) { | 505 ZoneList<Declaration*>* declarations) { |
| 531 int length = declarations->length(); | 506 int length = declarations->length(); |
| 532 int globals = 0; | 507 int global_count = 0; |
| 533 for (int i = 0; i < length; i++) { | 508 for (int i = 0; i < length; i++) { |
| 534 Declaration* decl = declarations->at(i); | 509 Declaration* decl = declarations->at(i); |
| 535 Variable* var = decl->proxy()->var(); | 510 EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count); |
| 536 Slot* slot = var->AsSlot(); | |
| 537 | |
| 538 // If it was not possible to allocate the variable at compile | |
| 539 // time, we need to "declare" it at runtime to make sure it | |
| 540 // actually exists in the local context. | |
| 541 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) { | |
| 542 VisitDeclaration(decl); | |
| 543 } else { | |
| 544 // Count global variables and functions for later processing | |
| 545 globals++; | |
| 546 } | |
| 547 } | 511 } |
| 548 | 512 |
| 549 // Compute array of global variable and function declarations. | 513 // Batch declare global functions and variables. |
| 550 // Do nothing in case of no declared global functions or variables. | 514 if (global_count > 0) { |
| 551 if (globals > 0) { | |
| 552 Handle<FixedArray> array = | 515 Handle<FixedArray> array = |
| 553 isolate()->factory()->NewFixedArray(2 * globals, TENURED); | 516 isolate()->factory()->NewFixedArray(2 * global_count, TENURED); |
| 554 for (int j = 0, i = 0; i < length; i++) { | 517 for (int j = 0, i = 0; i < length; i++) { |
| 555 Declaration* decl = declarations->at(i); | 518 Declaration* decl = declarations->at(i); |
| 556 Variable* var = decl->proxy()->var(); | 519 Variable* var = decl->proxy()->var(); |
| 557 Slot* slot = var->AsSlot(); | |
| 558 | 520 |
| 559 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) { | 521 if (var->IsUnallocated()) { |
| 560 array->set(j++, *(var->name())); | 522 array->set(j++, *(var->name())); |
| 561 if (decl->fun() == NULL) { | 523 if (decl->fun() == NULL) { |
| 562 if (var->mode() == Variable::CONST) { | 524 if (var->mode() == Variable::CONST) { |
| 563 // In case this is const property use the hole. | 525 // In case this is const property use the hole. |
| 564 array->set_the_hole(j++); | 526 array->set_the_hole(j++); |
| 565 } else { | 527 } else { |
| 566 array->set_undefined(j++); | 528 array->set_undefined(j++); |
| 567 } | 529 } |
| 568 } else { | 530 } else { |
| 569 Handle<SharedFunctionInfo> function = | 531 Handle<SharedFunctionInfo> function = |
| 570 Compiler::BuildFunctionInfo(decl->fun(), script()); | 532 Compiler::BuildFunctionInfo(decl->fun(), script()); |
| 571 // Check for stack-overflow exception. | 533 // Check for stack-overflow exception. |
| 572 if (function.is_null()) { | 534 if (function.is_null()) { |
| 573 SetStackOverflow(); | 535 SetStackOverflow(); |
| 574 return; | 536 return; |
| 575 } | 537 } |
| 576 array->set(j++, *function); | 538 array->set(j++, *function); |
| 577 } | 539 } |
| 578 } | 540 } |
| 579 } | 541 } |
| 580 // Invoke the platform-dependent code generator to do the actual | 542 // Invoke the platform-dependent code generator to do the actual |
| 581 // declaration the global variables and functions. | 543 // declaration the global functions and variables. |
| 582 DeclareGlobals(array); | 544 DeclareGlobals(array); |
| 583 } | 545 } |
| 584 } | 546 } |
| 585 | 547 |
| 586 | 548 |
| 549 int FullCodeGenerator::DeclareGlobalsFlags() { |
| 550 int flags = 0; |
| 551 if (is_eval()) flags |= kDeclareGlobalsEvalFlag; |
| 552 if (is_strict_mode()) flags |= kDeclareGlobalsStrictModeFlag; |
| 553 if (is_native()) flags |= kDeclareGlobalsNativeFlag; |
| 554 return flags; |
| 555 } |
| 556 |
| 557 |
| 587 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { | 558 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { |
| 588 CodeGenerator::RecordPositions(masm_, fun->start_position()); | 559 CodeGenerator::RecordPositions(masm_, fun->start_position()); |
| 589 } | 560 } |
| 590 | 561 |
| 591 | 562 |
| 592 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) { | 563 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) { |
| 593 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1); | 564 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1); |
| 594 } | 565 } |
| 595 | 566 |
| 596 | 567 |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 PrepareForBailout(expr, state); | 806 PrepareForBailout(expr, state); |
| 836 // Forwarding bailouts to children is a one shot operation. It should have | 807 // Forwarding bailouts to children is a one shot operation. It should have |
| 837 // been processed at this point. | 808 // been processed at this point. |
| 838 ASSERT(forward_bailout_pending_ == NULL); | 809 ASSERT(forward_bailout_pending_ == NULL); |
| 839 } | 810 } |
| 840 } | 811 } |
| 841 | 812 |
| 842 | 813 |
| 843 void FullCodeGenerator::VisitBlock(Block* stmt) { | 814 void FullCodeGenerator::VisitBlock(Block* stmt) { |
| 844 Comment cmnt(masm_, "[ Block"); | 815 Comment cmnt(masm_, "[ Block"); |
| 845 Breakable nested_statement(this, stmt); | 816 NestedBlock nested_block(this, stmt); |
| 846 SetStatementPosition(stmt); | 817 SetStatementPosition(stmt); |
| 847 | 818 |
| 848 Scope* saved_scope = scope(); | 819 Scope* saved_scope = scope(); |
| 820 // Push a block context when entering a block with block scoped variables. |
| 849 if (stmt->block_scope() != NULL) { | 821 if (stmt->block_scope() != NULL) { |
| 850 { Comment cmnt(masm_, "[ Extend block context"); | 822 { Comment cmnt(masm_, "[ Extend block context"); |
| 851 scope_ = stmt->block_scope(); | 823 scope_ = stmt->block_scope(); |
| 852 __ Push(scope_->GetSerializedScopeInfo()); | 824 __ Push(scope_->GetSerializedScopeInfo()); |
| 853 PushFunctionArgumentForContextAllocation(); | 825 PushFunctionArgumentForContextAllocation(); |
| 854 __ CallRuntime(Runtime::kPushBlockContext, 2); | 826 __ CallRuntime(Runtime::kPushBlockContext, 2); |
| 855 StoreToFrameField(StandardFrameConstants::kContextOffset, | 827 StoreToFrameField(StandardFrameConstants::kContextOffset, |
| 856 context_register()); | 828 context_register()); |
| 857 } | 829 } |
| 858 { Comment cmnt(masm_, "[ Declarations"); | 830 { Comment cmnt(masm_, "[ Declarations"); |
| 859 VisitDeclarations(scope_->declarations()); | 831 VisitDeclarations(scope_->declarations()); |
| 860 } | 832 } |
| 861 } | 833 } |
| 862 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 834 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 863 VisitStatements(stmt->statements()); | 835 VisitStatements(stmt->statements()); |
| 864 scope_ = saved_scope; | 836 scope_ = saved_scope; |
| 865 __ bind(nested_statement.break_label()); | 837 __ bind(nested_block.break_label()); |
| 866 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 838 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 839 |
| 840 // Pop block context if necessary. |
| 841 if (stmt->block_scope() != NULL) { |
| 842 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
| 843 // Update local stack frame context field. |
| 844 StoreToFrameField(StandardFrameConstants::kContextOffset, |
| 845 context_register()); |
| 846 } |
| 867 } | 847 } |
| 868 | 848 |
| 869 | 849 |
| 870 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | 850 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 871 Comment cmnt(masm_, "[ ExpressionStatement"); | 851 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 872 SetStatementPosition(stmt); | 852 SetStatementPosition(stmt); |
| 873 VisitForEffect(stmt->expression()); | 853 VisitForEffect(stmt->expression()); |
| 874 } | 854 } |
| 875 | 855 |
| 876 | 856 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 997 Visit(stmt->statement()); | 977 Visit(stmt->statement()); |
| 998 } | 978 } |
| 999 | 979 |
| 1000 // Pop context. | 980 // Pop context. |
| 1001 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | 981 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
| 1002 // Update local stack frame context field. | 982 // Update local stack frame context field. |
| 1003 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); | 983 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); |
| 1004 } | 984 } |
| 1005 | 985 |
| 1006 | 986 |
| 1007 void FullCodeGenerator::VisitExitContextStatement(ExitContextStatement* stmt) { | |
| 1008 Comment cmnt(masm_, "[ ExitContextStatement"); | |
| 1009 SetStatementPosition(stmt); | |
| 1010 | |
| 1011 // Pop context. | |
| 1012 LoadContextField(context_register(), Context::PREVIOUS_INDEX); | |
| 1013 // Update local stack frame context field. | |
| 1014 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); | |
| 1015 } | |
| 1016 | |
| 1017 | |
| 1018 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 987 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 1019 Comment cmnt(masm_, "[ DoWhileStatement"); | 988 Comment cmnt(masm_, "[ DoWhileStatement"); |
| 1020 SetStatementPosition(stmt); | 989 SetStatementPosition(stmt); |
| 1021 Label body, stack_check; | 990 Label body, stack_check; |
| 1022 | 991 |
| 1023 Iteration loop_statement(this, stmt); | 992 Iteration loop_statement(this, stmt); |
| 1024 increment_loop_depth(); | 993 increment_loop_depth(); |
| 1025 | 994 |
| 1026 __ bind(&body); | 995 __ bind(&body); |
| 1027 Visit(stmt->body()); | 996 Visit(stmt->body()); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1155 StoreToFrameField(StandardFrameConstants::kContextOffset, | 1124 StoreToFrameField(StandardFrameConstants::kContextOffset, |
| 1156 context_register()); | 1125 context_register()); |
| 1157 } | 1126 } |
| 1158 | 1127 |
| 1159 Scope* saved_scope = scope(); | 1128 Scope* saved_scope = scope(); |
| 1160 scope_ = stmt->scope(); | 1129 scope_ = stmt->scope(); |
| 1161 ASSERT(scope_->declarations()->is_empty()); | 1130 ASSERT(scope_->declarations()->is_empty()); |
| 1162 { WithOrCatch body(this); | 1131 { WithOrCatch body(this); |
| 1163 Visit(stmt->catch_block()); | 1132 Visit(stmt->catch_block()); |
| 1164 } | 1133 } |
| 1134 // Restore the context. |
| 1135 LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
| 1136 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); |
| 1165 scope_ = saved_scope; | 1137 scope_ = saved_scope; |
| 1166 __ jmp(&done); | 1138 __ jmp(&done); |
| 1167 | 1139 |
| 1168 // Try block code. Sets up the exception handler chain. | 1140 // Try block code. Sets up the exception handler chain. |
| 1169 __ bind(&try_handler_setup); | 1141 __ bind(&try_handler_setup); |
| 1170 { | 1142 { |
| 1171 const int delta = StackHandlerConstants::kSize / kPointerSize; | 1143 const int delta = StackHandlerConstants::kSize / kPointerSize; |
| 1172 TryCatch try_block(this); | 1144 TryCatch try_block(this); |
| 1173 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); | 1145 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); |
| 1174 increment_stack_height(delta); | 1146 increment_stack_height(delta); |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1329 Comment cmnt(masm_, "[ Throw"); | 1301 Comment cmnt(masm_, "[ Throw"); |
| 1330 // Throw has no effect on the stack height or the current expression context. | 1302 // Throw has no effect on the stack height or the current expression context. |
| 1331 // Usually the expression context is null, because throw is a statement. | 1303 // Usually the expression context is null, because throw is a statement. |
| 1332 VisitForStackValue(expr->exception()); | 1304 VisitForStackValue(expr->exception()); |
| 1333 __ CallRuntime(Runtime::kThrow, 1); | 1305 __ CallRuntime(Runtime::kThrow, 1); |
| 1334 decrement_stack_height(); | 1306 decrement_stack_height(); |
| 1335 // Never returns here. | 1307 // Never returns here. |
| 1336 } | 1308 } |
| 1337 | 1309 |
| 1338 | 1310 |
| 1339 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( | |
| 1340 int* stack_depth, | |
| 1341 int* context_length) { | |
| 1342 // The macros used here must preserve the result register. | |
| 1343 __ Drop(*stack_depth); | |
| 1344 __ PopTryHandler(); | |
| 1345 *stack_depth = 0; | |
| 1346 | |
| 1347 Register context = FullCodeGenerator::context_register(); | |
| 1348 while (*context_length > 0) { | |
| 1349 codegen_->LoadContextField(context, Context::PREVIOUS_INDEX); | |
| 1350 --(*context_length); | |
| 1351 } | |
| 1352 | |
| 1353 __ Call(finally_entry_); | |
| 1354 return previous_; | |
| 1355 } | |
| 1356 | |
| 1357 | |
| 1358 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit( | 1311 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit( |
| 1359 int* stack_depth, | 1312 int* stack_depth, |
| 1360 int* context_length) { | 1313 int* context_length) { |
| 1361 // The macros used here must preserve the result register. | 1314 // The macros used here must preserve the result register. |
| 1362 __ Drop(*stack_depth); | 1315 __ Drop(*stack_depth); |
| 1363 __ PopTryHandler(); | 1316 __ PopTryHandler(); |
| 1364 *stack_depth = 0; | 1317 *stack_depth = 0; |
| 1365 return previous_; | 1318 return previous_; |
| 1366 } | 1319 } |
| 1367 | 1320 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1383 } | 1336 } |
| 1384 | 1337 |
| 1385 return false; | 1338 return false; |
| 1386 } | 1339 } |
| 1387 | 1340 |
| 1388 | 1341 |
| 1389 #undef __ | 1342 #undef __ |
| 1390 | 1343 |
| 1391 | 1344 |
| 1392 } } // namespace v8::internal | 1345 } } // namespace v8::internal |
| OLD | NEW |