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