Home | History | Annotate | Download | only in src
      1 // Copyright 2009 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "codegen-inl.h"
     31 #include "compiler.h"
     32 #include "full-codegen.h"
     33 #include "stub-cache.h"
     34 #include "debug.h"
     35 #include "liveedit.h"
     36 
     37 namespace v8 {
     38 namespace internal {
     39 
     40 #define BAILOUT(reason)                         \
     41   do {                                          \
     42     if (FLAG_trace_bailout) {                   \
     43       PrintF("%s\n", reason);                   \
     44     }                                           \
     45     has_supported_syntax_ = false;              \
     46     return;                                     \
     47   } while (false)
     48 
     49 
     50 #define CHECK_BAILOUT                           \
     51   do {                                          \
     52     if (!has_supported_syntax_) return;         \
     53   } while (false)
     54 
     55 
     56 void FullCodeGenSyntaxChecker::Check(FunctionLiteral* fun) {
     57   Scope* scope = fun->scope();
     58   VisitDeclarations(scope->declarations());
     59   CHECK_BAILOUT;
     60 
     61   VisitStatements(fun->body());
     62 }
     63 
     64 
     65 void FullCodeGenSyntaxChecker::VisitDeclarations(
     66     ZoneList<Declaration*>* decls) {
     67   for (int i = 0; i < decls->length(); i++) {
     68     Visit(decls->at(i));
     69     CHECK_BAILOUT;
     70   }
     71 }
     72 
     73 
     74 void FullCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) {
     75   for (int i = 0, len = stmts->length(); i < len; i++) {
     76     Visit(stmts->at(i));
     77     CHECK_BAILOUT;
     78   }
     79 }
     80 
     81 
     82 void FullCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) {
     83   Property* prop = decl->proxy()->AsProperty();
     84   if (prop != NULL) {
     85     Visit(prop->obj());
     86     Visit(prop->key());
     87   }
     88 
     89   if (decl->fun() != NULL) {
     90     Visit(decl->fun());
     91   }
     92 }
     93 
     94 
     95 void FullCodeGenSyntaxChecker::VisitBlock(Block* stmt) {
     96   VisitStatements(stmt->statements());
     97 }
     98 
     99 
    100 void FullCodeGenSyntaxChecker::VisitExpressionStatement(
    101     ExpressionStatement* stmt) {
    102   Visit(stmt->expression());
    103 }
    104 
    105 
    106 void FullCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) {
    107   // Supported.
    108 }
    109 
    110 
    111 void FullCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) {
    112   Visit(stmt->condition());
    113   CHECK_BAILOUT;
    114   Visit(stmt->then_statement());
    115   CHECK_BAILOUT;
    116   Visit(stmt->else_statement());
    117 }
    118 
    119 
    120 void FullCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) {
    121   // Supported.
    122 }
    123 
    124 
    125 void FullCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) {
    126   // Supported.
    127 }
    128 
    129 
    130 void FullCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) {
    131   Visit(stmt->expression());
    132 }
    133 
    134 
    135 void FullCodeGenSyntaxChecker::VisitWithEnterStatement(
    136     WithEnterStatement* stmt) {
    137   Visit(stmt->expression());
    138 }
    139 
    140 
    141 void FullCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) {
    142   // Supported.
    143 }
    144 
    145 
    146 void FullCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) {
    147   BAILOUT("SwitchStatement");
    148 }
    149 
    150 
    151 void FullCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
    152   Visit(stmt->cond());
    153   CHECK_BAILOUT;
    154   Visit(stmt->body());
    155 }
    156 
    157 
    158 void FullCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) {
    159   Visit(stmt->cond());
    160   CHECK_BAILOUT;
    161   Visit(stmt->body());
    162 }
    163 
    164 
    165 void FullCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) {
    166   if (!FLAG_always_full_compiler) BAILOUT("ForStatement");
    167   if (stmt->init() != NULL) {
    168     Visit(stmt->init());
    169     CHECK_BAILOUT;
    170   }
    171   if (stmt->cond() != NULL) {
    172     Visit(stmt->cond());
    173     CHECK_BAILOUT;
    174   }
    175   Visit(stmt->body());
    176   if (stmt->next() != NULL) {
    177     CHECK_BAILOUT;
    178     Visit(stmt->next());
    179   }
    180 }
    181 
    182 
    183 void FullCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) {
    184   BAILOUT("ForInStatement");
    185 }
    186 
    187 
    188 void FullCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) {
    189   Visit(stmt->try_block());
    190   CHECK_BAILOUT;
    191   Visit(stmt->catch_block());
    192 }
    193 
    194 
    195 void FullCodeGenSyntaxChecker::VisitTryFinallyStatement(
    196     TryFinallyStatement* stmt) {
    197   Visit(stmt->try_block());
    198   CHECK_BAILOUT;
    199   Visit(stmt->finally_block());
    200 }
    201 
    202 
    203 void FullCodeGenSyntaxChecker::VisitDebuggerStatement(
    204     DebuggerStatement* stmt) {
    205   // Supported.
    206 }
    207 
    208 
    209 void FullCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
    210   // Supported.
    211 }
    212 
    213 
    214 void FullCodeGenSyntaxChecker::VisitFunctionBoilerplateLiteral(
    215     FunctionBoilerplateLiteral* expr) {
    216   BAILOUT("FunctionBoilerplateLiteral");
    217 }
    218 
    219 
    220 void FullCodeGenSyntaxChecker::VisitConditional(Conditional* expr) {
    221   Visit(expr->condition());
    222   CHECK_BAILOUT;
    223   Visit(expr->then_expression());
    224   CHECK_BAILOUT;
    225   Visit(expr->else_expression());
    226 }
    227 
    228 
    229 void FullCodeGenSyntaxChecker::VisitSlot(Slot* expr) {
    230   UNREACHABLE();
    231 }
    232 
    233 
    234 void FullCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
    235   // Supported.
    236 }
    237 
    238 
    239 void FullCodeGenSyntaxChecker::VisitLiteral(Literal* expr) {
    240   // Supported.
    241 }
    242 
    243 
    244 void FullCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
    245   // Supported.
    246 }
    247 
    248 
    249 void FullCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) {
    250   ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
    251 
    252   for (int i = 0, len = properties->length(); i < len; i++) {
    253     ObjectLiteral::Property* property = properties->at(i);
    254     if (property->IsCompileTimeValue()) continue;
    255     Visit(property->key());
    256     CHECK_BAILOUT;
    257     Visit(property->value());
    258     CHECK_BAILOUT;
    259   }
    260 }
    261 
    262 
    263 void FullCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) {
    264   ZoneList<Expression*>* subexprs = expr->values();
    265   for (int i = 0, len = subexprs->length(); i < len; i++) {
    266     Expression* subexpr = subexprs->at(i);
    267     if (subexpr->AsLiteral() != NULL) continue;
    268     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
    269     Visit(subexpr);
    270     CHECK_BAILOUT;
    271   }
    272 }
    273 
    274 
    275 void FullCodeGenSyntaxChecker::VisitCatchExtensionObject(
    276     CatchExtensionObject* expr) {
    277   Visit(expr->key());
    278   CHECK_BAILOUT;
    279   Visit(expr->value());
    280 }
    281 
    282 
    283 void FullCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
    284   Token::Value op = expr->op();
    285   if (op == Token::INIT_CONST) BAILOUT("initialize constant");
    286 
    287   Variable* var = expr->target()->AsVariableProxy()->AsVariable();
    288   Property* prop = expr->target()->AsProperty();
    289   ASSERT(var == NULL || prop == NULL);
    290   if (var != NULL) {
    291     if (var->mode() == Variable::CONST) BAILOUT("Assignment to const");
    292     // All other variables are supported.
    293   } else if (prop != NULL) {
    294     Visit(prop->obj());
    295     CHECK_BAILOUT;
    296     Visit(prop->key());
    297     CHECK_BAILOUT;
    298   } else {
    299     // This is a throw reference error.
    300     BAILOUT("non-variable/non-property assignment");
    301   }
    302 
    303   Visit(expr->value());
    304 }
    305 
    306 
    307 void FullCodeGenSyntaxChecker::VisitThrow(Throw* expr) {
    308   Visit(expr->exception());
    309 }
    310 
    311 
    312 void FullCodeGenSyntaxChecker::VisitProperty(Property* expr) {
    313   Visit(expr->obj());
    314   CHECK_BAILOUT;
    315   Visit(expr->key());
    316 }
    317 
    318 
    319 void FullCodeGenSyntaxChecker::VisitCall(Call* expr) {
    320   Expression* fun = expr->expression();
    321   ZoneList<Expression*>* args = expr->arguments();
    322   Variable* var = fun->AsVariableProxy()->AsVariable();
    323 
    324   // Check for supported calls
    325   if (var != NULL && var->is_possibly_eval()) {
    326     BAILOUT("call to the identifier 'eval'");
    327   } else if (var != NULL && !var->is_this() && var->is_global()) {
    328     // Calls to global variables are supported.
    329   } else if (var != NULL && var->slot() != NULL &&
    330              var->slot()->type() == Slot::LOOKUP) {
    331     BAILOUT("call to a lookup slot");
    332   } else if (fun->AsProperty() != NULL) {
    333     Property* prop = fun->AsProperty();
    334     Visit(prop->obj());
    335     CHECK_BAILOUT;
    336     Visit(prop->key());
    337     CHECK_BAILOUT;
    338   } else {
    339     // Otherwise the call is supported if the function expression is.
    340     Visit(fun);
    341   }
    342   // Check all arguments to the call.
    343   for (int i = 0; i < args->length(); i++) {
    344     Visit(args->at(i));
    345     CHECK_BAILOUT;
    346   }
    347 }
    348 
    349 
    350 void FullCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) {
    351   Visit(expr->expression());
    352   CHECK_BAILOUT;
    353   ZoneList<Expression*>* args = expr->arguments();
    354   // Check all arguments to the call
    355   for (int i = 0; i < args->length(); i++) {
    356     Visit(args->at(i));
    357     CHECK_BAILOUT;
    358   }
    359 }
    360 
    361 
    362 void FullCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) {
    363   // Check for inline runtime call
    364   if (expr->name()->Get(0) == '_' &&
    365       CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
    366     BAILOUT("inlined runtime call");
    367   }
    368   // Check all arguments to the call.  (Relies on TEMP meaning STACK.)
    369   for (int i = 0; i < expr->arguments()->length(); i++) {
    370     Visit(expr->arguments()->at(i));
    371     CHECK_BAILOUT;
    372   }
    373 }
    374 
    375 
    376 void FullCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) {
    377   switch (expr->op()) {
    378     case Token::ADD:
    379     case Token::BIT_NOT:
    380     case Token::NOT:
    381     case Token::SUB:
    382     case Token::TYPEOF:
    383     case Token::VOID:
    384       Visit(expr->expression());
    385       break;
    386     case Token::DELETE:
    387       BAILOUT("UnaryOperation: DELETE");
    388     default:
    389       UNREACHABLE();
    390   }
    391 }
    392 
    393 
    394 void FullCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) {
    395   Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
    396   Property* prop = expr->expression()->AsProperty();
    397   ASSERT(var == NULL || prop == NULL);
    398   if (var != NULL) {
    399     // All global variables are supported.
    400     if (!var->is_global()) {
    401       ASSERT(var->slot() != NULL);
    402       Slot::Type type = var->slot()->type();
    403       if (type == Slot::LOOKUP) {
    404         BAILOUT("CountOperation with lookup slot");
    405       }
    406     }
    407   } else if (prop != NULL) {
    408     Visit(prop->obj());
    409     CHECK_BAILOUT;
    410     Visit(prop->key());
    411     CHECK_BAILOUT;
    412   } else {
    413     // This is a throw reference error.
    414     BAILOUT("CountOperation non-variable/non-property expression");
    415   }
    416 }
    417 
    418 
    419 void FullCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) {
    420   Visit(expr->left());
    421   CHECK_BAILOUT;
    422   Visit(expr->right());
    423 }
    424 
    425 
    426 void FullCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) {
    427   Visit(expr->left());
    428   CHECK_BAILOUT;
    429   Visit(expr->right());
    430 }
    431 
    432 
    433 void FullCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
    434   // Supported.
    435 }
    436 
    437 #undef BAILOUT
    438 #undef CHECK_BAILOUT
    439 
    440 
    441 #define __ ACCESS_MASM(masm())
    442 
    443 Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
    444   Handle<Script> script = info->script();
    445   if (!script->IsUndefined() && !script->source()->IsUndefined()) {
    446     int len = String::cast(script->source())->length();
    447     Counters::total_full_codegen_source_size.Increment(len);
    448   }
    449   CodeGenerator::MakeCodePrologue(info);
    450   const int kInitialBufferSize = 4 * KB;
    451   MacroAssembler masm(NULL, kInitialBufferSize);
    452   LiveEditFunctionTracker live_edit_tracker(info->function());
    453 
    454   FullCodeGenerator cgen(&masm);
    455   cgen.Generate(info, PRIMARY);
    456   if (cgen.HasStackOverflow()) {
    457     ASSERT(!Top::has_pending_exception());
    458     return Handle<Code>::null();
    459   }
    460   Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
    461   Handle<Code> result = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
    462   live_edit_tracker.RecordFunctionCode(result);
    463   return result;
    464 }
    465 
    466 
    467 int FullCodeGenerator::SlotOffset(Slot* slot) {
    468   ASSERT(slot != NULL);
    469   // Offset is negative because higher indexes are at lower addresses.
    470   int offset = -slot->index() * kPointerSize;
    471   // Adjust by a (parameter or local) base offset.
    472   switch (slot->type()) {
    473     case Slot::PARAMETER:
    474       offset += (scope()->num_parameters() + 1) * kPointerSize;
    475       break;
    476     case Slot::LOCAL:
    477       offset += JavaScriptFrameConstants::kLocal0Offset;
    478       break;
    479     case Slot::CONTEXT:
    480     case Slot::LOOKUP:
    481       UNREACHABLE();
    482   }
    483   return offset;
    484 }
    485 
    486 
    487 void FullCodeGenerator::VisitDeclarations(
    488     ZoneList<Declaration*>* declarations) {
    489   int length = declarations->length();
    490   int globals = 0;
    491   for (int i = 0; i < length; i++) {
    492     Declaration* decl = declarations->at(i);
    493     Variable* var = decl->proxy()->var();
    494     Slot* slot = var->slot();
    495 
    496     // If it was not possible to allocate the variable at compile
    497     // time, we need to "declare" it at runtime to make sure it
    498     // actually exists in the local context.
    499     if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
    500       VisitDeclaration(decl);
    501     } else {
    502       // Count global variables and functions for later processing
    503       globals++;
    504     }
    505   }
    506 
    507   // Compute array of global variable and function declarations.
    508   // Do nothing in case of no declared global functions or variables.
    509   if (globals > 0) {
    510     Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
    511     for (int j = 0, i = 0; i < length; i++) {
    512       Declaration* decl = declarations->at(i);
    513       Variable* var = decl->proxy()->var();
    514       Slot* slot = var->slot();
    515 
    516       if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
    517         array->set(j++, *(var->name()));
    518         if (decl->fun() == NULL) {
    519           if (var->mode() == Variable::CONST) {
    520             // In case this is const property use the hole.
    521             array->set_the_hole(j++);
    522           } else {
    523             array->set_undefined(j++);
    524           }
    525         } else {
    526           Handle<JSFunction> function =
    527               Compiler::BuildBoilerplate(decl->fun(), script(), this);
    528           // Check for stack-overflow exception.
    529           if (HasStackOverflow()) return;
    530           array->set(j++, *function);
    531         }
    532       }
    533     }
    534     // Invoke the platform-dependent code generator to do the actual
    535     // declaration the global variables and functions.
    536     DeclareGlobals(array);
    537   }
    538 }
    539 
    540 
    541 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
    542   if (FLAG_debug_info) {
    543     CodeGenerator::RecordPositions(masm_, fun->start_position());
    544   }
    545 }
    546 
    547 
    548 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
    549   if (FLAG_debug_info) {
    550     CodeGenerator::RecordPositions(masm_, fun->end_position());
    551   }
    552 }
    553 
    554 
    555 void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
    556   if (FLAG_debug_info) {
    557     CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
    558   }
    559 }
    560 
    561 
    562 void FullCodeGenerator::SetStatementPosition(int pos) {
    563   if (FLAG_debug_info) {
    564     CodeGenerator::RecordPositions(masm_, pos);
    565   }
    566 }
    567 
    568 
    569 void FullCodeGenerator::SetSourcePosition(int pos) {
    570   if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
    571     masm_->RecordPosition(pos);
    572   }
    573 }
    574 
    575 
    576 void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
    577   Label eval_right, done;
    578 
    579   // Set up the appropriate context for the left subexpression based
    580   // on the operation and our own context.  Initially assume we can
    581   // inherit both true and false labels from our context.
    582   if (expr->op() == Token::OR) {
    583     switch (context_) {
    584       case Expression::kUninitialized:
    585         UNREACHABLE();
    586       case Expression::kEffect:
    587         VisitForControl(expr->left(), &done, &eval_right);
    588         break;
    589       case Expression::kValue:
    590         VisitForValueControl(expr->left(),
    591                              location_,
    592                              &done,
    593                              &eval_right);
    594         break;
    595       case Expression::kTest:
    596         VisitForControl(expr->left(), true_label_, &eval_right);
    597         break;
    598       case Expression::kValueTest:
    599         VisitForValueControl(expr->left(),
    600                              location_,
    601                              true_label_,
    602                              &eval_right);
    603         break;
    604       case Expression::kTestValue:
    605         VisitForControl(expr->left(), true_label_, &eval_right);
    606         break;
    607     }
    608   } else {
    609     ASSERT_EQ(Token::AND, expr->op());
    610     switch (context_) {
    611       case Expression::kUninitialized:
    612         UNREACHABLE();
    613       case Expression::kEffect:
    614         VisitForControl(expr->left(), &eval_right, &done);
    615         break;
    616       case Expression::kValue:
    617         VisitForControlValue(expr->left(),
    618                              location_,
    619                              &eval_right,
    620                              &done);
    621         break;
    622       case Expression::kTest:
    623         VisitForControl(expr->left(), &eval_right, false_label_);
    624         break;
    625       case Expression::kValueTest:
    626         VisitForControl(expr->left(), &eval_right, false_label_);
    627         break;
    628       case Expression::kTestValue:
    629         VisitForControlValue(expr->left(),
    630                              location_,
    631                              &eval_right,
    632                              false_label_);
    633         break;
    634     }
    635   }
    636 
    637   __ bind(&eval_right);
    638   Visit(expr->right());
    639 
    640   __ bind(&done);
    641 }
    642 
    643 
    644 void FullCodeGenerator::VisitBlock(Block* stmt) {
    645   Comment cmnt(masm_, "[ Block");
    646   Breakable nested_statement(this, stmt);
    647   SetStatementPosition(stmt);
    648   VisitStatements(stmt->statements());
    649   __ bind(nested_statement.break_target());
    650 }
    651 
    652 
    653 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
    654   Comment cmnt(masm_, "[ ExpressionStatement");
    655   SetStatementPosition(stmt);
    656   VisitForEffect(stmt->expression());
    657 }
    658 
    659 
    660 void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
    661   Comment cmnt(masm_, "[ EmptyStatement");
    662   SetStatementPosition(stmt);
    663 }
    664 
    665 
    666 void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
    667   Comment cmnt(masm_, "[ IfStatement");
    668   SetStatementPosition(stmt);
    669   Label then_part, else_part, done;
    670 
    671   // Do not worry about optimizing for empty then or else bodies.
    672   VisitForControl(stmt->condition(), &then_part, &else_part);
    673 
    674   __ bind(&then_part);
    675   Visit(stmt->then_statement());
    676   __ jmp(&done);
    677 
    678   __ bind(&else_part);
    679   Visit(stmt->else_statement());
    680 
    681   __ bind(&done);
    682 }
    683 
    684 
    685 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
    686   Comment cmnt(masm_,  "[ ContinueStatement");
    687   SetStatementPosition(stmt);
    688   NestedStatement* current = nesting_stack_;
    689   int stack_depth = 0;
    690   while (!current->IsContinueTarget(stmt->target())) {
    691     stack_depth = current->Exit(stack_depth);
    692     current = current->outer();
    693   }
    694   __ Drop(stack_depth);
    695 
    696   Iteration* loop = current->AsIteration();
    697   __ jmp(loop->continue_target());
    698 }
    699 
    700 
    701 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
    702   Comment cmnt(masm_,  "[ BreakStatement");
    703   SetStatementPosition(stmt);
    704   NestedStatement* current = nesting_stack_;
    705   int stack_depth = 0;
    706   while (!current->IsBreakTarget(stmt->target())) {
    707     stack_depth = current->Exit(stack_depth);
    708     current = current->outer();
    709   }
    710   __ Drop(stack_depth);
    711 
    712   Breakable* target = current->AsBreakable();
    713   __ jmp(target->break_target());
    714 }
    715 
    716 
    717 void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
    718   Comment cmnt(masm_, "[ ReturnStatement");
    719   SetStatementPosition(stmt);
    720   Expression* expr = stmt->expression();
    721   VisitForValue(expr, kAccumulator);
    722 
    723   // Exit all nested statements.
    724   NestedStatement* current = nesting_stack_;
    725   int stack_depth = 0;
    726   while (current != NULL) {
    727     stack_depth = current->Exit(stack_depth);
    728     current = current->outer();
    729   }
    730   __ Drop(stack_depth);
    731 
    732   EmitReturnSequence(stmt->statement_pos());
    733 }
    734 
    735 
    736 void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
    737   Comment cmnt(masm_, "[ WithEnterStatement");
    738   SetStatementPosition(stmt);
    739 
    740   VisitForValue(stmt->expression(), kStack);
    741   if (stmt->is_catch_block()) {
    742     __ CallRuntime(Runtime::kPushCatchContext, 1);
    743   } else {
    744     __ CallRuntime(Runtime::kPushContext, 1);
    745   }
    746   // Both runtime calls return the new context in both the context and the
    747   // result registers.
    748 
    749   // Update local stack frame context field.
    750   StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
    751 }
    752 
    753 
    754 void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
    755   Comment cmnt(masm_, "[ WithExitStatement");
    756   SetStatementPosition(stmt);
    757 
    758   // Pop context.
    759   LoadContextField(context_register(), Context::PREVIOUS_INDEX);
    760   // Update local stack frame context field.
    761   StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
    762 }
    763 
    764 
    765 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
    766   UNREACHABLE();
    767 }
    768 
    769 
    770 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
    771   Comment cmnt(masm_, "[ DoWhileStatement");
    772   SetStatementPosition(stmt);
    773   Label body, stack_limit_hit, stack_check_success;
    774 
    775   Iteration loop_statement(this, stmt);
    776   increment_loop_depth();
    777 
    778   __ bind(&body);
    779   Visit(stmt->body());
    780 
    781   // Check stack before looping.
    782   __ StackLimitCheck(&stack_limit_hit);
    783   __ bind(&stack_check_success);
    784 
    785   __ bind(loop_statement.continue_target());
    786   SetStatementPosition(stmt->condition_position());
    787   VisitForControl(stmt->cond(), &body, loop_statement.break_target());
    788 
    789   __ bind(&stack_limit_hit);
    790   StackCheckStub stack_stub;
    791   __ CallStub(&stack_stub);
    792   __ jmp(&stack_check_success);
    793 
    794   __ bind(loop_statement.break_target());
    795 
    796   decrement_loop_depth();
    797 }
    798 
    799 
    800 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
    801   Comment cmnt(masm_, "[ WhileStatement");
    802   SetStatementPosition(stmt);
    803   Label body, stack_limit_hit, stack_check_success;
    804 
    805   Iteration loop_statement(this, stmt);
    806   increment_loop_depth();
    807 
    808   // Emit the test at the bottom of the loop.
    809   __ jmp(loop_statement.continue_target());
    810 
    811   __ bind(&body);
    812   Visit(stmt->body());
    813 
    814   __ bind(loop_statement.continue_target());
    815   // Check stack before looping.
    816   __ StackLimitCheck(&stack_limit_hit);
    817   __ bind(&stack_check_success);
    818 
    819   VisitForControl(stmt->cond(), &body, loop_statement.break_target());
    820 
    821   __ bind(&stack_limit_hit);
    822   StackCheckStub stack_stub;
    823   __ CallStub(&stack_stub);
    824   __ jmp(&stack_check_success);
    825 
    826   __ bind(loop_statement.break_target());
    827   decrement_loop_depth();
    828 }
    829 
    830 
    831 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
    832   Comment cmnt(masm_, "[ ForStatement");
    833   SetStatementPosition(stmt);
    834   Label test, body, stack_limit_hit, stack_check_success;
    835 
    836   Iteration loop_statement(this, stmt);
    837   if (stmt->init() != NULL) {
    838     Visit(stmt->init());
    839   }
    840 
    841   increment_loop_depth();
    842   // Emit the test at the bottom of the loop (even if empty).
    843   __ jmp(&test);
    844 
    845   __ bind(&body);
    846   Visit(stmt->body());
    847 
    848   __ bind(loop_statement.continue_target());
    849 
    850   SetStatementPosition(stmt);
    851   if (stmt->next() != NULL) {
    852     Visit(stmt->next());
    853   }
    854 
    855   __ bind(&test);
    856 
    857   // Check stack before looping.
    858   __ StackLimitCheck(&stack_limit_hit);
    859   __ bind(&stack_check_success);
    860 
    861   if (stmt->cond() != NULL) {
    862     VisitForControl(stmt->cond(), &body, loop_statement.break_target());
    863   } else {
    864     __ jmp(&body);
    865   }
    866 
    867   __ bind(&stack_limit_hit);
    868   StackCheckStub stack_stub;
    869   __ CallStub(&stack_stub);
    870   __ jmp(&stack_check_success);
    871 
    872   __ bind(loop_statement.break_target());
    873   decrement_loop_depth();
    874 }
    875 
    876 
    877 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
    878   UNREACHABLE();
    879 }
    880 
    881 
    882 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
    883   Comment cmnt(masm_, "[ TryCatchStatement");
    884   SetStatementPosition(stmt);
    885   // The try block adds a handler to the exception handler chain
    886   // before entering, and removes it again when exiting normally.
    887   // If an exception is thrown during execution of the try block,
    888   // control is passed to the handler, which also consumes the handler.
    889   // At this point, the exception is in a register, and store it in
    890   // the temporary local variable (prints as ".catch-var") before
    891   // executing the catch block. The catch block has been rewritten
    892   // to introduce a new scope to bind the catch variable and to remove
    893   // that scope again afterwards.
    894 
    895   Label try_handler_setup, catch_entry, done;
    896   __ Call(&try_handler_setup);
    897   // Try handler code, exception in result register.
    898 
    899   // Store exception in local .catch variable before executing catch block.
    900   {
    901     // The catch variable is *always* a variable proxy for a local variable.
    902     Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
    903     ASSERT_NOT_NULL(catch_var);
    904     Slot* variable_slot = catch_var->slot();
    905     ASSERT_NOT_NULL(variable_slot);
    906     ASSERT_EQ(Slot::LOCAL, variable_slot->type());
    907     StoreToFrameField(SlotOffset(variable_slot), result_register());
    908   }
    909 
    910   Visit(stmt->catch_block());
    911   __ jmp(&done);
    912 
    913   // Try block code. Sets up the exception handler chain.
    914   __ bind(&try_handler_setup);
    915   {
    916     TryCatch try_block(this, &catch_entry);
    917     __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
    918     Visit(stmt->try_block());
    919     __ PopTryHandler();
    920   }
    921   __ bind(&done);
    922 }
    923 
    924 
    925 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
    926   Comment cmnt(masm_, "[ TryFinallyStatement");
    927   SetStatementPosition(stmt);
    928   // Try finally is compiled by setting up a try-handler on the stack while
    929   // executing the try body, and removing it again afterwards.
    930   //
    931   // The try-finally construct can enter the finally block in three ways:
    932   // 1. By exiting the try-block normally. This removes the try-handler and
    933   //      calls the finally block code before continuing.
    934   // 2. By exiting the try-block with a function-local control flow transfer
    935   //    (break/continue/return). The site of the, e.g., break removes the
    936   //    try handler and calls the finally block code before continuing
    937   //    its outward control transfer.
    938   // 3. by exiting the try-block with a thrown exception.
    939   //    This can happen in nested function calls. It traverses the try-handler
    940   //    chain and consumes the try-handler entry before jumping to the
    941   //    handler code. The handler code then calls the finally-block before
    942   //    rethrowing the exception.
    943   //
    944   // The finally block must assume a return address on top of the stack
    945   // (or in the link register on ARM chips) and a value (return value or
    946   // exception) in the result register (rax/eax/r0), both of which must
    947   // be preserved. The return address isn't GC-safe, so it should be
    948   // cooked before GC.
    949   Label finally_entry;
    950   Label try_handler_setup;
    951 
    952   // Setup the try-handler chain. Use a call to
    953   // Jump to try-handler setup and try-block code. Use call to put try-handler
    954   // address on stack.
    955   __ Call(&try_handler_setup);
    956   // Try handler code. Return address of call is pushed on handler stack.
    957   {
    958     // This code is only executed during stack-handler traversal when an
    959     // exception is thrown. The execption is in the result register, which
    960     // is retained by the finally block.
    961     // Call the finally block and then rethrow the exception.
    962     __ Call(&finally_entry);
    963     __ push(result_register());
    964     __ CallRuntime(Runtime::kReThrow, 1);
    965   }
    966 
    967   __ bind(&finally_entry);
    968   {
    969     // Finally block implementation.
    970     Finally finally_block(this);
    971     EnterFinallyBlock();
    972     Visit(stmt->finally_block());
    973     ExitFinallyBlock();  // Return to the calling code.
    974   }
    975 
    976   __ bind(&try_handler_setup);
    977   {
    978     // Setup try handler (stack pointer registers).
    979     TryFinally try_block(this, &finally_entry);
    980     __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
    981     Visit(stmt->try_block());
    982     __ PopTryHandler();
    983   }
    984   // Execute the finally block on the way out.
    985   __ Call(&finally_entry);
    986 }
    987 
    988 
    989 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
    990 #ifdef ENABLE_DEBUGGER_SUPPORT
    991   Comment cmnt(masm_, "[ DebuggerStatement");
    992   SetStatementPosition(stmt);
    993 
    994   __ DebugBreak();
    995   // Ignore the return value.
    996 #endif
    997 }
    998 
    999 
   1000 void FullCodeGenerator::VisitFunctionBoilerplateLiteral(
   1001     FunctionBoilerplateLiteral* expr) {
   1002   UNREACHABLE();
   1003 }
   1004 
   1005 
   1006 void FullCodeGenerator::VisitConditional(Conditional* expr) {
   1007   Comment cmnt(masm_, "[ Conditional");
   1008   Label true_case, false_case, done;
   1009   VisitForControl(expr->condition(), &true_case, &false_case);
   1010 
   1011   __ bind(&true_case);
   1012   Visit(expr->then_expression());
   1013   // If control flow falls through Visit, jump to done.
   1014   if (context_ == Expression::kEffect || context_ == Expression::kValue) {
   1015     __ jmp(&done);
   1016   }
   1017 
   1018   __ bind(&false_case);
   1019   Visit(expr->else_expression());
   1020   // If control flow falls through Visit, merge it with true case here.
   1021   if (context_ == Expression::kEffect || context_ == Expression::kValue) {
   1022     __ bind(&done);
   1023   }
   1024 }
   1025 
   1026 
   1027 void FullCodeGenerator::VisitSlot(Slot* expr) {
   1028   // Slots do not appear directly in the AST.
   1029   UNREACHABLE();
   1030 }
   1031 
   1032 
   1033 void FullCodeGenerator::VisitLiteral(Literal* expr) {
   1034   Comment cmnt(masm_, "[ Literal");
   1035   Apply(context_, expr);
   1036 }
   1037 
   1038 
   1039 void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
   1040   // Call runtime routine to allocate the catch extension object and
   1041   // assign the exception value to the catch variable.
   1042   Comment cmnt(masm_, "[ CatchExtensionObject");
   1043   VisitForValue(expr->key(), kStack);
   1044   VisitForValue(expr->value(), kStack);
   1045   // Create catch extension object.
   1046   __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
   1047   Apply(context_, result_register());
   1048 }
   1049 
   1050 
   1051 void FullCodeGenerator::VisitThrow(Throw* expr) {
   1052   Comment cmnt(masm_, "[ Throw");
   1053   VisitForValue(expr->exception(), kStack);
   1054   __ CallRuntime(Runtime::kThrow, 1);
   1055   // Never returns here.
   1056 }
   1057 
   1058 
   1059 int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
   1060   // The macros used here must preserve the result register.
   1061   __ Drop(stack_depth);
   1062   __ PopTryHandler();
   1063   __ Call(finally_entry_);
   1064   return 0;
   1065 }
   1066 
   1067 
   1068 int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
   1069   // The macros used here must preserve the result register.
   1070   __ Drop(stack_depth);
   1071   __ PopTryHandler();
   1072   return 0;
   1073 }
   1074 
   1075 #undef __
   1076 
   1077 
   1078 } }  // namespace v8::internal
   1079