Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 JumpTarget* false_target, | 358 JumpTarget* false_target, |
| 359 bool force_cc) { | 359 bool force_cc) { |
| 360 ASSERT(!has_cc()); | 360 ASSERT(!has_cc()); |
| 361 | 361 |
| 362 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 362 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 363 Visit(x); | 363 Visit(x); |
| 364 } | 364 } |
| 365 | 365 |
| 366 if (force_cc && frame_ != NULL && !has_cc()) { | 366 if (force_cc && frame_ != NULL && !has_cc()) { |
| 367 // Convert the TOS value to a boolean in the condition code register. | 367 // Convert the TOS value to a boolean in the condition code register. |
| 368 frame_->SpillAll(); | |
| 368 ToBoolean(true_target, false_target); | 369 ToBoolean(true_target, false_target); |
| 369 } | 370 } |
| 370 | 371 |
| 371 ASSERT(!force_cc || frame_ == NULL || has_cc()); | 372 ASSERT(!force_cc || frame_ == NULL || has_cc()); |
| 372 } | 373 } |
| 373 | 374 |
| 374 | 375 |
| 375 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 376 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 376 JumpTarget true_target(this); | 377 JumpTarget true_target(this); |
| 377 JumpTarget false_target(this); | 378 JumpTarget false_target(this); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 442 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
| 442 // NOTE: This is somewhat nasty. We force the compiler to load | 443 // NOTE: This is somewhat nasty. We force the compiler to load |
| 443 // the variable as if through '<global>.<variable>' to make sure we | 444 // the variable as if through '<global>.<variable>' to make sure we |
| 444 // do not get reference errors. | 445 // do not get reference errors. |
| 445 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 446 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
| 446 Literal key(variable->name()); | 447 Literal key(variable->name()); |
| 447 // TODO(1241834): Fetch the position from the variable instead of using | 448 // TODO(1241834): Fetch the position from the variable instead of using |
| 448 // no position. | 449 // no position. |
| 449 Property property(&global, &key, RelocInfo::kNoPosition); | 450 Property property(&global, &key, RelocInfo::kNoPosition); |
| 450 Load(&property); | 451 Load(&property); |
| 452 frame_->SpillAll(); | |
| 451 } else { | 453 } else { |
| 452 Load(x, INSIDE_TYPEOF); | 454 Load(x, INSIDE_TYPEOF); |
| 455 frame_->SpillAll(); | |
| 453 } | 456 } |
| 454 } | 457 } |
| 455 | 458 |
| 456 | 459 |
| 457 Reference::Reference(CodeGenerator* cgen, Expression* expression) | 460 Reference::Reference(CodeGenerator* cgen, Expression* expression) |
| 458 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 461 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
| 459 cgen->LoadReference(this); | 462 cgen->LoadReference(this); |
| 460 } | 463 } |
| 461 | 464 |
| 462 | 465 |
| 463 Reference::~Reference() { | 466 Reference::~Reference() { |
| 464 cgen_->UnloadReference(this); | 467 cgen_->UnloadReference(this); |
| 465 } | 468 } |
| 466 | 469 |
| 467 | 470 |
| 468 void CodeGenerator::LoadReference(Reference* ref) { | 471 void CodeGenerator::LoadReference(Reference* ref) { |
| 469 Comment cmnt(masm_, "[ LoadReference"); | 472 Comment cmnt(masm_, "[ LoadReference"); |
| 470 Expression* e = ref->expression(); | 473 Expression* e = ref->expression(); |
| 471 Property* property = e->AsProperty(); | 474 Property* property = e->AsProperty(); |
| 472 Variable* var = e->AsVariableProxy()->AsVariable(); | 475 Variable* var = e->AsVariableProxy()->AsVariable(); |
| 473 | 476 |
| 474 if (property != NULL) { | 477 if (property != NULL) { |
| 475 // The expression is either a property or a variable proxy that rewrites | 478 // The expression is either a property or a variable proxy that rewrites |
| 476 // to a property. | 479 // to a property. |
| 477 Load(property->obj()); | 480 Load(property->obj()); |
| 481 frame_->SpillAll(); | |
| 478 // We use a named reference if the key is a literal symbol, unless it is | 482 // We use a named reference if the key is a literal symbol, unless it is |
| 479 // a string that can be legally parsed as an integer. This is because | 483 // a string that can be legally parsed as an integer. This is because |
| 480 // otherwise we will not get into the slow case code that handles [] on | 484 // otherwise we will not get into the slow case code that handles [] on |
| 481 // String objects. | 485 // String objects. |
| 482 Literal* literal = property->key()->AsLiteral(); | 486 Literal* literal = property->key()->AsLiteral(); |
| 483 uint32_t dummy; | 487 uint32_t dummy; |
| 484 if (literal != NULL && | 488 if (literal != NULL && |
| 485 literal->handle()->IsSymbol() && | 489 literal->handle()->IsSymbol() && |
| 486 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { | 490 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { |
| 487 ref->set_type(Reference::NAMED); | 491 ref->set_type(Reference::NAMED); |
| 488 } else { | 492 } else { |
| 489 Load(property->key()); | 493 Load(property->key()); |
| 494 frame_->SpillAll(); | |
| 490 ref->set_type(Reference::KEYED); | 495 ref->set_type(Reference::KEYED); |
| 491 } | 496 } |
| 492 } else if (var != NULL) { | 497 } else if (var != NULL) { |
| 493 // The expression is a variable proxy that does not rewrite to a | 498 // The expression is a variable proxy that does not rewrite to a |
| 494 // property. Global variables are treated as named property references. | 499 // property. Global variables are treated as named property references. |
| 495 if (var->is_global()) { | 500 if (var->is_global()) { |
| 496 LoadGlobal(); | 501 LoadGlobal(); |
| 497 ref->set_type(Reference::NAMED); | 502 ref->set_type(Reference::NAMED); |
| 498 } else { | 503 } else { |
| 499 ASSERT(var->slot() != NULL); | 504 ASSERT(var->slot() != NULL); |
| 500 ref->set_type(Reference::SLOT); | 505 ref->set_type(Reference::SLOT); |
| 501 } | 506 } |
| 502 } else { | 507 } else { |
| 503 // Anything else is a runtime error. | 508 // Anything else is a runtime error. |
| 504 Load(e); | 509 Load(e); |
| 510 frame_->SpillAll(); | |
| 505 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); | 511 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); |
| 506 } | 512 } |
| 507 } | 513 } |
| 508 | 514 |
| 509 | 515 |
| 510 void CodeGenerator::UnloadReference(Reference* ref) { | 516 void CodeGenerator::UnloadReference(Reference* ref) { |
| 511 // Pop a reference from the stack while preserving TOS. | 517 // Pop a reference from the stack while preserving TOS. |
| 512 Comment cmnt(masm_, "[ UnloadReference"); | 518 Comment cmnt(masm_, "[ UnloadReference"); |
| 513 int size = ref->size(); | 519 int size = ref->size(); |
| 514 if (size == 1) { | 520 if (size == 1) { |
| (...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1217 | 1223 |
| 1218 | 1224 |
| 1219 // Call the function just below TOS on the stack with the given | 1225 // Call the function just below TOS on the stack with the given |
| 1220 // arguments. The receiver is the TOS. | 1226 // arguments. The receiver is the TOS. |
| 1221 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1227 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
| 1222 int position) { | 1228 int position) { |
| 1223 // Push the arguments ("left-to-right") on the stack. | 1229 // Push the arguments ("left-to-right") on the stack. |
| 1224 int arg_count = args->length(); | 1230 int arg_count = args->length(); |
| 1225 for (int i = 0; i < arg_count; i++) { | 1231 for (int i = 0; i < arg_count; i++) { |
| 1226 Load(args->at(i)); | 1232 Load(args->at(i)); |
| 1233 frame_->SpillAll(); | |
| 1227 } | 1234 } |
| 1228 | 1235 |
| 1229 // Record the position for debugging purposes. | 1236 // Record the position for debugging purposes. |
| 1230 __ RecordPosition(position); | 1237 __ RecordPosition(position); |
| 1231 | 1238 |
| 1232 // Use the shared code stub to call the function. | 1239 // Use the shared code stub to call the function. |
| 1233 CallFunctionStub call_function(arg_count); | 1240 CallFunctionStub call_function(arg_count); |
| 1234 frame_->CallStub(&call_function, arg_count + 1); | 1241 frame_->CallStub(&call_function, arg_count + 1); |
| 1235 | 1242 |
| 1236 // Restore context and pop function from the stack. | 1243 // Restore context and pop function from the stack. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1314 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1321 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| 1315 frame_->EmitPush(Immediate(Smi::FromInt(attr))); | 1322 frame_->EmitPush(Immediate(Smi::FromInt(attr))); |
| 1316 // Push initial value, if any. | 1323 // Push initial value, if any. |
| 1317 // Note: For variables we must not push an initial value (such as | 1324 // Note: For variables we must not push an initial value (such as |
| 1318 // 'undefined') because we may have a (legal) redeclaration and we | 1325 // 'undefined') because we may have a (legal) redeclaration and we |
| 1319 // must not destroy the current value. | 1326 // must not destroy the current value. |
| 1320 if (node->mode() == Variable::CONST) { | 1327 if (node->mode() == Variable::CONST) { |
| 1321 frame_->EmitPush(Immediate(Factory::the_hole_value())); | 1328 frame_->EmitPush(Immediate(Factory::the_hole_value())); |
| 1322 } else if (node->fun() != NULL) { | 1329 } else if (node->fun() != NULL) { |
| 1323 Load(node->fun()); | 1330 Load(node->fun()); |
| 1331 frame_->SpillAll(); | |
| 1324 } else { | 1332 } else { |
| 1325 frame_->EmitPush(Immediate(0)); // no initial value! | 1333 frame_->EmitPush(Immediate(0)); // no initial value! |
| 1326 } | 1334 } |
| 1327 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 1335 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 1328 // Ignore the return value (declarations are statements). | 1336 // Ignore the return value (declarations are statements). |
| 1329 return; | 1337 return; |
| 1330 } | 1338 } |
| 1331 | 1339 |
| 1332 ASSERT(!var->is_global()); | 1340 ASSERT(!var->is_global()); |
| 1333 | 1341 |
| 1334 // If we have a function or a constant, we need to initialize the variable. | 1342 // If we have a function or a constant, we need to initialize the variable. |
| 1335 Expression* val = NULL; | 1343 Expression* val = NULL; |
| 1336 if (node->mode() == Variable::CONST) { | 1344 if (node->mode() == Variable::CONST) { |
| 1337 val = new Literal(Factory::the_hole_value()); | 1345 val = new Literal(Factory::the_hole_value()); |
| 1338 } else { | 1346 } else { |
| 1339 val = node->fun(); // NULL if we don't have a function | 1347 val = node->fun(); // NULL if we don't have a function |
| 1340 } | 1348 } |
| 1341 | 1349 |
| 1342 if (val != NULL) { | 1350 if (val != NULL) { |
| 1343 // Set initial value. | 1351 // Set initial value. |
| 1344 Reference target(this, node->proxy()); | 1352 Reference target(this, node->proxy()); |
| 1345 ASSERT(target.is_slot()); | 1353 ASSERT(target.is_slot()); |
| 1346 Load(val); | 1354 Load(val); |
| 1355 frame_->SpillAll(); | |
| 1347 target.SetValue(NOT_CONST_INIT); | 1356 target.SetValue(NOT_CONST_INIT); |
| 1348 // Get rid of the assigned value (declarations are statements). It's | 1357 // Get rid of the assigned value (declarations are statements). It's |
| 1349 // safe to pop the value lying on top of the reference before unloading | 1358 // safe to pop the value lying on top of the reference before unloading |
| 1350 // the reference itself (which preserves the top of stack) because we | 1359 // the reference itself (which preserves the top of stack) because we |
| 1351 // know that it is a zero-sized reference. | 1360 // know that it is a zero-sized reference. |
| 1352 frame_->Drop(); | 1361 frame_->Drop(); |
| 1353 } | 1362 } |
| 1354 } | 1363 } |
| 1355 | 1364 |
| 1356 | 1365 |
| 1357 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1366 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1358 frame_->SpillAll(); | |
| 1359 Comment cmnt(masm_, "[ ExpressionStatement"); | 1367 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1360 RecordStatementPosition(node); | 1368 RecordStatementPosition(node); |
| 1361 Expression* expression = node->expression(); | 1369 Expression* expression = node->expression(); |
| 1362 expression->MarkAsStatement(); | 1370 expression->MarkAsStatement(); |
| 1363 Load(expression); | 1371 Load(expression); |
| 1364 // Remove the lingering expression result from the top of stack. | 1372 // Remove the lingering expression result from the top of stack. |
| 1365 frame_->Drop(); | 1373 frame_->Drop(); |
| 1374 // Rather than using SpillAll after all recursive calls to Visit over | |
| 1375 // statements, we spill here in the only statement type that uses the | |
| 1376 // virtual frame. This is temporary. | |
| 1377 frame_->SpillAll(); | |
| 1366 } | 1378 } |
| 1367 | 1379 |
| 1368 | 1380 |
| 1369 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1381 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1370 frame_->SpillAll(); | 1382 frame_->SpillAll(); |
| 1371 Comment cmnt(masm_, "// EmptyStatement"); | 1383 Comment cmnt(masm_, "// EmptyStatement"); |
| 1372 // nothing to do | 1384 // nothing to do |
| 1373 } | 1385 } |
| 1374 | 1386 |
| 1375 | 1387 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1441 if (frame_ != NULL || else_.is_linked()) { | 1453 if (frame_ != NULL || else_.is_linked()) { |
| 1442 else_.Bind(); | 1454 else_.Bind(); |
| 1443 Visit(node->else_statement()); | 1455 Visit(node->else_statement()); |
| 1444 } | 1456 } |
| 1445 | 1457 |
| 1446 } else { | 1458 } else { |
| 1447 ASSERT(!has_then_stm && !has_else_stm); | 1459 ASSERT(!has_then_stm && !has_else_stm); |
| 1448 // if (cond) | 1460 // if (cond) |
| 1449 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1461 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
| 1450 if (frame_ != NULL) { | 1462 if (frame_ != NULL) { |
| 1463 frame_->SpillAll(); | |
| 1451 if (has_cc()) { | 1464 if (has_cc()) { |
| 1452 cc_reg_ = no_condition; | 1465 cc_reg_ = no_condition; |
| 1453 } else { | 1466 } else { |
| 1454 // No cc value set up, that means the boolean was pushed. | 1467 // No cc value set up, that means the boolean was pushed. |
| 1455 // Pop it again, since it is not going to be used. | 1468 // Pop it again, since it is not going to be used. |
| 1456 frame_->Drop(); | 1469 frame_->Drop(); |
| 1457 } | 1470 } |
| 1458 } | 1471 } |
| 1459 } | 1472 } |
| 1460 | 1473 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1487 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1500 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1488 node->target()->break_target()->Jump(); | 1501 node->target()->break_target()->Jump(); |
| 1489 } | 1502 } |
| 1490 | 1503 |
| 1491 | 1504 |
| 1492 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1505 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1493 frame_->SpillAll(); | 1506 frame_->SpillAll(); |
| 1494 Comment cmnt(masm_, "[ ReturnStatement"); | 1507 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1495 RecordStatementPosition(node); | 1508 RecordStatementPosition(node); |
| 1496 Load(node->expression()); | 1509 Load(node->expression()); |
| 1510 frame_->SpillAll(); | |
| 1497 | 1511 |
| 1498 // Move the function result into eax | 1512 // Move the function result into eax |
| 1499 frame_->EmitPop(eax); | 1513 frame_->EmitPop(eax); |
| 1500 | 1514 |
| 1501 // If we're inside a try statement or the return instruction | 1515 // If we're inside a try statement or the return instruction |
| 1502 // sequence has been generated, we just jump to that | 1516 // sequence has been generated, we just jump to that |
| 1503 // point. Otherwise, we generate the return instruction sequence and | 1517 // point. Otherwise, we generate the return instruction sequence and |
| 1504 // bind the function return label. | 1518 // bind the function return label. |
| 1505 if (is_inside_try_ || function_return_.is_bound()) { | 1519 if (is_inside_try_ || function_return_.is_bound()) { |
| 1506 function_return_.Jump(); | 1520 function_return_.Jump(); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1527 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1541 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 1528 } | 1542 } |
| 1529 } | 1543 } |
| 1530 | 1544 |
| 1531 | 1545 |
| 1532 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1546 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1533 frame_->SpillAll(); | 1547 frame_->SpillAll(); |
| 1534 Comment cmnt(masm_, "[ WithEnterStatement"); | 1548 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1535 RecordStatementPosition(node); | 1549 RecordStatementPosition(node); |
| 1536 Load(node->expression()); | 1550 Load(node->expression()); |
| 1551 frame_->SpillAll(); | |
| 1537 frame_->CallRuntime(Runtime::kPushContext, 1); | 1552 frame_->CallRuntime(Runtime::kPushContext, 1); |
| 1538 | 1553 |
| 1539 if (kDebug) { | 1554 if (kDebug) { |
| 1540 JumpTarget verified_true(this); | 1555 JumpTarget verified_true(this); |
| 1541 // Verify eax and esi are the same in debug mode | 1556 // Verify eax and esi are the same in debug mode |
| 1542 __ cmp(eax, Operand(esi)); | 1557 __ cmp(eax, Operand(esi)); |
| 1543 verified_true.Branch(equal); | 1558 verified_true.Branch(equal); |
| 1544 __ int3(); | 1559 __ int3(); |
| 1545 verified_true.Bind(); | 1560 verified_true.Bind(); |
| 1546 } | 1561 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1638 | 1653 |
| 1639 | 1654 |
| 1640 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1655 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1641 frame_->SpillAll(); | 1656 frame_->SpillAll(); |
| 1642 Comment cmnt(masm_, "[ SwitchStatement"); | 1657 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1643 RecordStatementPosition(node); | 1658 RecordStatementPosition(node); |
| 1644 node->set_break_stack_height(break_stack_height_); | 1659 node->set_break_stack_height(break_stack_height_); |
| 1645 node->break_target()->set_code_generator(this); | 1660 node->break_target()->set_code_generator(this); |
| 1646 | 1661 |
| 1647 Load(node->tag()); | 1662 Load(node->tag()); |
| 1663 frame_->SpillAll(); | |
| 1648 | 1664 |
| 1649 if (TryGenerateFastCaseSwitchStatement(node)) { | 1665 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1650 return; | 1666 return; |
| 1651 } | 1667 } |
| 1652 | 1668 |
| 1653 JumpTarget next_test(this); | 1669 JumpTarget next_test(this); |
| 1654 JumpTarget fall_through(this); | 1670 JumpTarget fall_through(this); |
| 1655 JumpTarget default_entry(this); | 1671 JumpTarget default_entry(this); |
| 1656 JumpTarget default_exit(this); | 1672 JumpTarget default_exit(this); |
| 1657 ZoneList<CaseClause*>* cases = node->cases(); | 1673 ZoneList<CaseClause*>* cases = node->cases(); |
| 1658 int length = cases->length(); | 1674 int length = cases->length(); |
| 1659 CaseClause* default_clause = NULL; | 1675 CaseClause* default_clause = NULL; |
| 1660 | 1676 |
| 1661 for (int i = 0; i < length; i++) { | 1677 for (int i = 0; i < length; i++) { |
| 1662 CaseClause* clause = cases->at(i); | 1678 CaseClause* clause = cases->at(i); |
| 1663 if (clause->is_default()) { | 1679 if (clause->is_default()) { |
| 1664 // Remember the default clause and compile it at the end. | 1680 // Remember the default clause and compile it at the end. |
| 1665 default_clause = clause; | 1681 default_clause = clause; |
| 1666 continue; | 1682 continue; |
| 1667 } | 1683 } |
| 1668 | 1684 |
| 1669 Comment cmnt(masm_, "[ Case clause"); | 1685 Comment cmnt(masm_, "[ Case clause"); |
| 1670 // Compile the test. | 1686 // Compile the test. |
| 1671 next_test.Bind(); | 1687 next_test.Bind(); |
| 1672 next_test.Unuse(); | 1688 next_test.Unuse(); |
| 1673 // Duplicate TOS. | 1689 // Duplicate TOS. |
| 1674 __ mov(eax, frame_->Top()); | 1690 __ mov(eax, frame_->Top()); |
| 1675 frame_->EmitPush(eax); | 1691 frame_->EmitPush(eax); |
| 1676 Load(clause->label()); | 1692 Load(clause->label()); |
| 1693 frame_->SpillAll(); | |
| 1677 Comparison(equal, true); | 1694 Comparison(equal, true); |
| 1678 Branch(false, &next_test); | 1695 Branch(false, &next_test); |
| 1679 | 1696 |
| 1680 // Before entering the body from the test, remove the switch value from | 1697 // Before entering the body from the test, remove the switch value from |
| 1681 // the stack. | 1698 // the stack. |
| 1682 frame_->Drop(); | 1699 frame_->Drop(); |
| 1683 | 1700 |
| 1684 // Label the body so that fall through is enabled. | 1701 // Label the body so that fall through is enabled. |
| 1685 if (i > 0 && cases->at(i - 1)->is_default()) { | 1702 if (i > 0 && cases->at(i - 1)->is_default()) { |
| 1686 default_exit.Bind(); | 1703 default_exit.Bind(); |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1923 JumpTarget primitive(this); | 1940 JumpTarget primitive(this); |
| 1924 JumpTarget jsobject(this); | 1941 JumpTarget jsobject(this); |
| 1925 JumpTarget fixed_array(this); | 1942 JumpTarget fixed_array(this); |
| 1926 JumpTarget entry(this); | 1943 JumpTarget entry(this); |
| 1927 JumpTarget end_del_check(this); | 1944 JumpTarget end_del_check(this); |
| 1928 JumpTarget cleanup(this); | 1945 JumpTarget cleanup(this); |
| 1929 JumpTarget exit(this); | 1946 JumpTarget exit(this); |
| 1930 | 1947 |
| 1931 // Get the object to enumerate over (converted to JSObject). | 1948 // Get the object to enumerate over (converted to JSObject). |
| 1932 Load(node->enumerable()); | 1949 Load(node->enumerable()); |
| 1950 frame_->SpillAll(); | |
| 1933 | 1951 |
| 1934 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1952 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 1935 // to the specification. 12.6.4 mandates a call to ToObject. | 1953 // to the specification. 12.6.4 mandates a call to ToObject. |
| 1936 frame_->EmitPop(eax); | 1954 frame_->EmitPop(eax); |
| 1937 | 1955 |
| 1938 // eax: value to be iterated over | 1956 // eax: value to be iterated over |
| 1939 __ cmp(eax, Factory::undefined_value()); | 1957 __ cmp(eax, Factory::undefined_value()); |
| 1940 exit.Branch(equal); | 1958 exit.Branch(equal); |
| 1941 __ cmp(eax, Factory::null_value()); | 1959 __ cmp(eax, Factory::null_value()); |
| 1942 exit.Branch(equal); | 1960 exit.Branch(equal); |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2407 JumpTarget then(this); | 2425 JumpTarget then(this); |
| 2408 JumpTarget else_(this); | 2426 JumpTarget else_(this); |
| 2409 JumpTarget exit(this); | 2427 JumpTarget exit(this); |
| 2410 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 2428 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 2411 if (frame_ != NULL) { | 2429 if (frame_ != NULL) { |
| 2412 Branch(false, &else_); | 2430 Branch(false, &else_); |
| 2413 } | 2431 } |
| 2414 if (frame_ != NULL || then.is_linked()) { | 2432 if (frame_ != NULL || then.is_linked()) { |
| 2415 then.Bind(); | 2433 then.Bind(); |
| 2416 Load(node->then_expression(), typeof_state()); | 2434 Load(node->then_expression(), typeof_state()); |
| 2435 frame_->SpillAll(); | |
| 2417 exit.Jump(); | 2436 exit.Jump(); |
| 2418 } | 2437 } |
| 2419 if (else_.is_linked()) { | 2438 if (else_.is_linked()) { |
| 2420 else_.Bind(); | 2439 else_.Bind(); |
| 2421 Load(node->else_expression(), typeof_state()); | 2440 Load(node->else_expression(), typeof_state()); |
| 2441 frame_->SpillAll(); | |
| 2422 } | 2442 } |
| 2423 exit.Bind(); | 2443 exit.Bind(); |
| 2424 } | 2444 } |
| 2425 | 2445 |
| 2426 | 2446 |
| 2427 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2447 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2428 if (slot->type() == Slot::LOOKUP) { | 2448 if (slot->type() == Slot::LOOKUP) { |
| 2429 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2449 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2430 | 2450 |
| 2431 // For now, just do a runtime call. | 2451 // For now, just do a runtime call. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 2455 __ mov(eax, Factory::undefined_value()); | 2475 __ mov(eax, Factory::undefined_value()); |
| 2456 exit.Bind(); | 2476 exit.Bind(); |
| 2457 frame_->EmitPush(eax); | 2477 frame_->EmitPush(eax); |
| 2458 } else { | 2478 } else { |
| 2459 frame_->EmitPush(SlotOperand(slot, ecx)); | 2479 frame_->EmitPush(SlotOperand(slot, ecx)); |
| 2460 } | 2480 } |
| 2461 } | 2481 } |
| 2462 } | 2482 } |
| 2463 | 2483 |
| 2464 | 2484 |
| 2485 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | |
| 2486 if (slot->type() == Slot::LOOKUP) { | |
| 2487 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | |
| 2488 | |
| 2489 // For now, just do a runtime call. | |
| 2490 frame_->SpillAll(); | |
| 2491 frame_->EmitPush(frame_->Context()); | |
| 2492 frame_->EmitPush(Immediate(slot->var()->name())); | |
| 2493 | |
| 2494 if (init_state == CONST_INIT) { | |
| 2495 // Same as the case for a normal store, but ignores attribute | |
| 2496 // (e.g. READ_ONLY) of context slot so that we can initialize const | |
| 2497 // properties (introduced via eval("const foo = (some expr);")). Also, | |
| 2498 // uses the current function context instead of the top context. | |
| 2499 // | |
| 2500 // Note that we must declare the foo upon entry of eval(), via a | |
| 2501 // context slot declaration, but we cannot initialize it at the same | |
| 2502 // time, because the const declaration may be at the end of the eval | |
| 2503 // code (sigh...) and the const variable may have been used before | |
| 2504 // (where its value is 'undefined'). Thus, we can only do the | |
| 2505 // initialization when we actually encounter the expression and when | |
| 2506 // the expression operands are defined and valid, and thus we need the | |
| 2507 // split into 2 operations: declaration of the context slot followed | |
| 2508 // by initialization. | |
| 2509 frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
| 2510 } else { | |
| 2511 frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | |
| 2512 } | |
| 2513 // Storing a variable must keep the (new) value on the expression | |
| 2514 // stack. This is necessary for compiling chained assignment | |
| 2515 // expressions. | |
| 2516 frame_->EmitPush(eax); | |
| 2517 | |
| 2518 } else { | |
| 2519 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | |
| 2520 | |
| 2521 JumpTarget exit(this); | |
| 2522 if (init_state == CONST_INIT) { | |
| 2523 ASSERT(slot->var()->mode() == Variable::CONST); | |
| 2524 // Only the first const initialization must be executed (the slot | |
| 2525 // still contains 'the hole' value). When the assignment is executed, | |
| 2526 // the code is identical to a normal store (see below). | |
| 2527 Comment cmnt(masm_, "[ Init const"); | |
| 2528 frame_->SpillAll(); | |
| 2529 __ mov(eax, SlotOperand(slot, ecx)); | |
| 2530 __ cmp(eax, Factory::the_hole_value()); | |
| 2531 exit.Branch(not_equal); | |
| 2532 } | |
| 2533 | |
| 2534 // We must execute the store. Storing a variable must keep the (new) | |
| 2535 // value on the stack. This is necessary for compiling assignment | |
| 2536 // expressions. | |
| 2537 // | |
| 2538 // Note: We will reach here even with slot->var()->mode() == | |
| 2539 // Variable::CONST because of const declarations which will initialize | |
| 2540 // consts to 'the hole' value and by doing so, end up calling this code. | |
| 2541 if (slot->type() == Slot::PARAMETER) { | |
| 2542 frame_->StoreToParameterAt(slot->index()); | |
| 2543 } else if (slot->type() == Slot::LOCAL) { | |
| 2544 frame_->StoreToLocalAt(slot->index()); | |
| 2545 } else { | |
| 2546 // The other slot types (LOOKUP and GLOBAL) cannot reach here. | |
| 2547 ASSERT(slot->type() == Slot::CONTEXT); | |
| 2548 frame_->SpillAll(); | |
| 2549 frame_->EmitPop(eax); | |
| 2550 __ mov(SlotOperand(slot, ecx), eax); | |
| 2551 frame_->EmitPush(eax); // RecordWrite may destroy the value in eax. | |
| 2552 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
| 2553 __ RecordWrite(ecx, offset, eax, ebx); | |
| 2554 } | |
| 2555 | |
| 2556 // If we definitely did not jump over the assignment, we do not need | |
| 2557 // to bind the exit label. Doing so can defeat peephole | |
| 2558 // optimization. | |
| 2559 if (init_state == CONST_INIT) { | |
| 2560 exit.Bind(); | |
| 2561 } | |
| 2562 } | |
| 2563 } | |
| 2564 | |
| 2565 | |
| 2465 void CodeGenerator::VisitSlot(Slot* node) { | 2566 void CodeGenerator::VisitSlot(Slot* node) { |
| 2466 frame_->SpillAll(); | 2567 frame_->SpillAll(); |
| 2467 Comment cmnt(masm_, "[ Slot"); | 2568 Comment cmnt(masm_, "[ Slot"); |
| 2468 LoadFromSlot(node, typeof_state()); | 2569 LoadFromSlot(node, typeof_state()); |
| 2469 } | 2570 } |
| 2470 | 2571 |
| 2471 | 2572 |
| 2472 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2573 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 2473 frame_->SpillAll(); | 2574 frame_->SpillAll(); |
| 2474 Comment cmnt(masm_, "[ VariableProxy"); | 2575 Comment cmnt(masm_, "[ VariableProxy"); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 2486 ASSERT(frame_ != NULL); | 2587 ASSERT(frame_ != NULL); |
| 2487 } else { | 2588 } else { |
| 2488 ASSERT(var->is_global()); | 2589 ASSERT(var->is_global()); |
| 2489 Reference ref(this, node); | 2590 Reference ref(this, node); |
| 2490 ref.GetValue(typeof_state()); | 2591 ref.GetValue(typeof_state()); |
| 2491 } | 2592 } |
| 2492 } | 2593 } |
| 2493 | 2594 |
| 2494 | 2595 |
| 2495 void CodeGenerator::VisitLiteral(Literal* node) { | 2596 void CodeGenerator::VisitLiteral(Literal* node) { |
| 2496 frame_->SpillAll(); | |
| 2497 Comment cmnt(masm_, "[ Literal"); | 2597 Comment cmnt(masm_, "[ Literal"); |
| 2498 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 2598 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
| 2499 // To prevent long attacker-controlled byte sequences in code, larger | 2599 // To prevent long attacker-controlled byte sequences in code, larger |
| 2500 // Smis are loaded in two steps. | 2600 // Smis are loaded in two steps via a temporary register. |
|
William Hesse
2008/11/28 10:32:45
Is now the time for special-casing small literals,
Kevin Millikin (Chromium)
2008/11/28 12:19:08
It's only the non-"InlineSmi" literals that are lo
| |
| 2601 Register temp = allocator_->Allocate(); | |
| 2501 int bits = reinterpret_cast<int>(*node->handle()); | 2602 int bits = reinterpret_cast<int>(*node->handle()); |
| 2502 __ mov(eax, bits & 0x0000FFFF); | 2603 ASSERT(!temp.is(no_reg)); |
| 2503 __ xor_(eax, bits & 0xFFFF0000); | 2604 __ mov(temp, bits & 0x0000FFFF); |
| 2504 frame_->EmitPush(eax); | 2605 __ xor_(temp, bits & 0xFFFF0000); |
| 2606 frame_->Push(temp); | |
| 2607 allocator_->Unuse(temp); | |
| 2505 } else { | 2608 } else { |
| 2506 frame_->EmitPush(Immediate(node->handle())); | 2609 frame_->Push(node->handle()); |
| 2507 } | 2610 } |
| 2508 } | 2611 } |
| 2509 | 2612 |
| 2510 | 2613 |
| 2511 class RegExpDeferred: public DeferredCode { | 2614 class RegExpDeferred: public DeferredCode { |
| 2512 public: | 2615 public: |
| 2513 RegExpDeferred(CodeGenerator* generator, RegExpLiteral* node) | 2616 RegExpDeferred(CodeGenerator* generator, RegExpLiteral* node) |
| 2514 : DeferredCode(generator), node_(node) { | 2617 : DeferredCode(generator), node_(node) { |
| 2515 set_comment("[ RegExpDeferred"); | 2618 set_comment("[ RegExpDeferred"); |
| 2516 } | 2619 } |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2634 ObjectLiteral::Property* property = node->properties()->at(i); | 2737 ObjectLiteral::Property* property = node->properties()->at(i); |
| 2635 switch (property->kind()) { | 2738 switch (property->kind()) { |
| 2636 case ObjectLiteral::Property::CONSTANT: break; | 2739 case ObjectLiteral::Property::CONSTANT: break; |
| 2637 case ObjectLiteral::Property::COMPUTED: { | 2740 case ObjectLiteral::Property::COMPUTED: { |
| 2638 Handle<Object> key(property->key()->handle()); | 2741 Handle<Object> key(property->key()->handle()); |
| 2639 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2742 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 2640 if (key->IsSymbol()) { | 2743 if (key->IsSymbol()) { |
| 2641 __ mov(eax, frame_->Top()); | 2744 __ mov(eax, frame_->Top()); |
| 2642 frame_->EmitPush(eax); | 2745 frame_->EmitPush(eax); |
| 2643 Load(property->value()); | 2746 Load(property->value()); |
| 2747 frame_->SpillAll(); | |
| 2644 frame_->EmitPop(eax); | 2748 frame_->EmitPop(eax); |
| 2645 __ Set(ecx, Immediate(key)); | 2749 __ Set(ecx, Immediate(key)); |
| 2646 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 2750 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 2647 frame_->Drop(); | 2751 frame_->Drop(); |
| 2648 // Ignore result. | 2752 // Ignore result. |
| 2649 break; | 2753 break; |
| 2650 } | 2754 } |
| 2651 // Fall through | 2755 // Fall through |
| 2652 } | 2756 } |
| 2653 case ObjectLiteral::Property::PROTOTYPE: { | 2757 case ObjectLiteral::Property::PROTOTYPE: { |
| 2654 __ mov(eax, frame_->Top()); | 2758 __ mov(eax, frame_->Top()); |
| 2655 frame_->EmitPush(eax); | 2759 frame_->EmitPush(eax); |
| 2656 Load(property->key()); | 2760 Load(property->key()); |
| 2761 frame_->SpillAll(); | |
| 2657 Load(property->value()); | 2762 Load(property->value()); |
| 2763 frame_->SpillAll(); | |
| 2658 frame_->CallRuntime(Runtime::kSetProperty, 3); | 2764 frame_->CallRuntime(Runtime::kSetProperty, 3); |
| 2659 // Ignore result. | 2765 // Ignore result. |
| 2660 break; | 2766 break; |
| 2661 } | 2767 } |
| 2662 case ObjectLiteral::Property::SETTER: { | 2768 case ObjectLiteral::Property::SETTER: { |
| 2663 // Duplicate the resulting object on the stack. The runtime | 2769 // Duplicate the resulting object on the stack. The runtime |
| 2664 // function will pop the three arguments passed in. | 2770 // function will pop the three arguments passed in. |
| 2665 __ mov(eax, frame_->Top()); | 2771 __ mov(eax, frame_->Top()); |
| 2666 frame_->EmitPush(eax); | 2772 frame_->EmitPush(eax); |
| 2667 Load(property->key()); | 2773 Load(property->key()); |
| 2774 frame_->SpillAll(); | |
| 2668 frame_->EmitPush(Immediate(Smi::FromInt(1))); | 2775 frame_->EmitPush(Immediate(Smi::FromInt(1))); |
| 2669 Load(property->value()); | 2776 Load(property->value()); |
| 2777 frame_->SpillAll(); | |
| 2670 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 2778 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2671 // Ignore result. | 2779 // Ignore result. |
| 2672 break; | 2780 break; |
| 2673 } | 2781 } |
| 2674 case ObjectLiteral::Property::GETTER: { | 2782 case ObjectLiteral::Property::GETTER: { |
| 2675 // Duplicate the resulting object on the stack. The runtime | 2783 // Duplicate the resulting object on the stack. The runtime |
| 2676 // function will pop the three arguments passed in. | 2784 // function will pop the three arguments passed in. |
| 2677 __ mov(eax, frame_->Top()); | 2785 __ mov(eax, frame_->Top()); |
| 2678 frame_->EmitPush(eax); | 2786 frame_->EmitPush(eax); |
| 2679 Load(property->key()); | 2787 Load(property->key()); |
| 2788 frame_->SpillAll(); | |
| 2680 frame_->EmitPush(Immediate(Smi::FromInt(0))); | 2789 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 2681 Load(property->value()); | 2790 Load(property->value()); |
| 2791 frame_->SpillAll(); | |
| 2682 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 2792 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2683 // Ignore result. | 2793 // Ignore result. |
| 2684 break; | 2794 break; |
| 2685 } | 2795 } |
| 2686 default: UNREACHABLE(); | 2796 default: UNREACHABLE(); |
| 2687 } | 2797 } |
| 2688 } | 2798 } |
| 2689 } | 2799 } |
| 2690 | 2800 |
| 2691 | 2801 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2708 // Generate code to set the elements in the array that are not | 2818 // Generate code to set the elements in the array that are not |
| 2709 // literals. | 2819 // literals. |
| 2710 for (int i = 0; i < node->values()->length(); i++) { | 2820 for (int i = 0; i < node->values()->length(); i++) { |
| 2711 Expression* value = node->values()->at(i); | 2821 Expression* value = node->values()->at(i); |
| 2712 | 2822 |
| 2713 // If value is literal the property value is already | 2823 // If value is literal the property value is already |
| 2714 // set in the boilerplate object. | 2824 // set in the boilerplate object. |
| 2715 if (value->AsLiteral() == NULL) { | 2825 if (value->AsLiteral() == NULL) { |
| 2716 // The property must be set by generated code. | 2826 // The property must be set by generated code. |
| 2717 Load(value); | 2827 Load(value); |
| 2828 frame_->SpillAll(); | |
| 2718 | 2829 |
| 2719 // Get the value off the stack. | 2830 // Get the value off the stack. |
| 2720 frame_->EmitPop(eax); | 2831 frame_->EmitPop(eax); |
| 2721 // Fetch the object literal while leaving on the stack. | 2832 // Fetch the object literal while leaving on the stack. |
| 2722 __ mov(ecx, frame_->Top()); | 2833 __ mov(ecx, frame_->Top()); |
| 2723 // Get the elements array. | 2834 // Get the elements array. |
| 2724 __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); | 2835 __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); |
| 2725 | 2836 |
| 2726 // Write to the indexed properties array. | 2837 // Write to the indexed properties array. |
| 2727 int offset = i * kPointerSize + Array::kHeaderSize; | 2838 int offset = i * kPointerSize + Array::kHeaderSize; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2760 Load(node->value()); | 2871 Load(node->value()); |
| 2761 | 2872 |
| 2762 } else { | 2873 } else { |
| 2763 target.GetValue(NOT_INSIDE_TYPEOF); | 2874 target.GetValue(NOT_INSIDE_TYPEOF); |
| 2764 Literal* literal = node->value()->AsLiteral(); | 2875 Literal* literal = node->value()->AsLiteral(); |
| 2765 if (IsInlineSmi(literal)) { | 2876 if (IsInlineSmi(literal)) { |
| 2766 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, | 2877 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, |
| 2767 NO_OVERWRITE); | 2878 NO_OVERWRITE); |
| 2768 } else { | 2879 } else { |
| 2769 Load(node->value()); | 2880 Load(node->value()); |
| 2881 frame_->SpillAll(); | |
| 2770 GenericBinaryOperation(node->binary_op(), node->type()); | 2882 GenericBinaryOperation(node->binary_op(), node->type()); |
| 2771 } | 2883 } |
| 2772 } | 2884 } |
| 2773 | 2885 |
| 2774 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 2886 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 2775 if (var != NULL && | 2887 if (var != NULL && |
| 2776 var->mode() == Variable::CONST && | 2888 var->mode() == Variable::CONST && |
| 2777 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 2889 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
| 2778 // Assignment ignored - leave the value on the stack. | 2890 // Assignment ignored - leave the value on the stack. |
| 2779 } else { | 2891 } else { |
| 2780 __ RecordPosition(node->position()); | 2892 __ RecordPosition(node->position()); |
| 2781 if (node->op() == Token::INIT_CONST) { | 2893 if (node->op() == Token::INIT_CONST) { |
| 2782 // Dynamic constant initializations must use the function context | 2894 // Dynamic constant initializations must use the function context |
| 2783 // and initialize the actual constant declared. Dynamic variable | 2895 // and initialize the actual constant declared. Dynamic variable |
| 2784 // initializations are simply assignments and use SetValue. | 2896 // initializations are simply assignments and use SetValue. |
| 2785 target.SetValue(CONST_INIT); | 2897 target.SetValue(CONST_INIT); |
| 2786 } else { | 2898 } else { |
| 2787 target.SetValue(NOT_CONST_INIT); | 2899 target.SetValue(NOT_CONST_INIT); |
| 2788 } | 2900 } |
| 2789 } | 2901 } |
| 2790 } | 2902 } |
| 2791 } | 2903 } |
| 2792 | 2904 |
| 2793 | 2905 |
| 2794 void CodeGenerator::VisitThrow(Throw* node) { | 2906 void CodeGenerator::VisitThrow(Throw* node) { |
| 2795 frame_->SpillAll(); | 2907 frame_->SpillAll(); |
| 2796 Comment cmnt(masm_, "[ Throw"); | 2908 Comment cmnt(masm_, "[ Throw"); |
| 2797 | 2909 |
| 2798 Load(node->exception()); | 2910 Load(node->exception()); |
| 2911 frame_->SpillAll(); | |
| 2799 __ RecordPosition(node->position()); | 2912 __ RecordPosition(node->position()); |
| 2800 frame_->CallRuntime(Runtime::kThrow, 1); | 2913 frame_->CallRuntime(Runtime::kThrow, 1); |
| 2801 frame_->EmitPush(eax); | 2914 frame_->EmitPush(eax); |
| 2802 } | 2915 } |
| 2803 | 2916 |
| 2804 | 2917 |
| 2805 void CodeGenerator::VisitProperty(Property* node) { | 2918 void CodeGenerator::VisitProperty(Property* node) { |
| 2806 frame_->SpillAll(); | 2919 frame_->SpillAll(); |
| 2807 Comment cmnt(masm_, "[ Property"); | 2920 Comment cmnt(masm_, "[ Property"); |
| 2808 Reference property(this, node); | 2921 Reference property(this, node); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2841 frame_->EmitPush(Immediate(var->name())); | 2954 frame_->EmitPush(Immediate(var->name())); |
| 2842 | 2955 |
| 2843 // Pass the global object as the receiver and let the IC stub | 2956 // Pass the global object as the receiver and let the IC stub |
| 2844 // patch the stack to use the global proxy as 'this' in the | 2957 // patch the stack to use the global proxy as 'this' in the |
| 2845 // invoked function. | 2958 // invoked function. |
| 2846 LoadGlobal(); | 2959 LoadGlobal(); |
| 2847 // Load the arguments. | 2960 // Load the arguments. |
| 2848 int arg_count = args->length(); | 2961 int arg_count = args->length(); |
| 2849 for (int i = 0; i < arg_count; i++) { | 2962 for (int i = 0; i < arg_count; i++) { |
| 2850 Load(args->at(i)); | 2963 Load(args->at(i)); |
| 2964 frame_->SpillAll(); | |
| 2851 } | 2965 } |
| 2852 | 2966 |
| 2853 // Setup the receiver register and call the IC initialization code. | 2967 // Setup the receiver register and call the IC initialization code. |
| 2854 Handle<Code> stub = (loop_nesting() > 0) | 2968 Handle<Code> stub = (loop_nesting() > 0) |
| 2855 ? ComputeCallInitializeInLoop(arg_count) | 2969 ? ComputeCallInitializeInLoop(arg_count) |
| 2856 : ComputeCallInitialize(arg_count); | 2970 : ComputeCallInitialize(arg_count); |
| 2857 __ RecordPosition(node->position()); | 2971 __ RecordPosition(node->position()); |
| 2858 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, | 2972 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, |
| 2859 arg_count + 1); | 2973 arg_count + 1); |
| 2860 __ mov(esi, frame_->Context()); | 2974 __ mov(esi, frame_->Context()); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 2886 Literal* literal = property->key()->AsLiteral(); | 3000 Literal* literal = property->key()->AsLiteral(); |
| 2887 | 3001 |
| 2888 if (literal != NULL && literal->handle()->IsSymbol()) { | 3002 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 2889 // ------------------------------------------------------------------ | 3003 // ------------------------------------------------------------------ |
| 2890 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 3004 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
| 2891 // ------------------------------------------------------------------ | 3005 // ------------------------------------------------------------------ |
| 2892 | 3006 |
| 2893 // Push the name of the function and the receiver onto the stack. | 3007 // Push the name of the function and the receiver onto the stack. |
| 2894 frame_->EmitPush(Immediate(literal->handle())); | 3008 frame_->EmitPush(Immediate(literal->handle())); |
| 2895 Load(property->obj()); | 3009 Load(property->obj()); |
| 3010 frame_->SpillAll(); | |
| 2896 | 3011 |
| 2897 // Load the arguments. | 3012 // Load the arguments. |
| 2898 int arg_count = args->length(); | 3013 int arg_count = args->length(); |
| 2899 for (int i = 0; i < arg_count; i++) { | 3014 for (int i = 0; i < arg_count; i++) { |
| 2900 Load(args->at(i)); | 3015 Load(args->at(i)); |
| 3016 frame_->SpillAll(); | |
| 2901 } | 3017 } |
| 2902 | 3018 |
| 2903 // Call the IC initialization code. | 3019 // Call the IC initialization code. |
| 2904 Handle<Code> stub = (loop_nesting() > 0) | 3020 Handle<Code> stub = (loop_nesting() > 0) |
| 2905 ? ComputeCallInitializeInLoop(arg_count) | 3021 ? ComputeCallInitializeInLoop(arg_count) |
| 2906 : ComputeCallInitialize(arg_count); | 3022 : ComputeCallInitialize(arg_count); |
| 2907 __ RecordPosition(node->position()); | 3023 __ RecordPosition(node->position()); |
| 2908 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); | 3024 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 2909 __ mov(esi, frame_->Context()); | 3025 __ mov(esi, frame_->Context()); |
| 2910 | 3026 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 2928 CallWithArguments(args, node->position()); | 3044 CallWithArguments(args, node->position()); |
| 2929 } | 3045 } |
| 2930 | 3046 |
| 2931 } else { | 3047 } else { |
| 2932 // ---------------------------------- | 3048 // ---------------------------------- |
| 2933 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 3049 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
| 2934 // ---------------------------------- | 3050 // ---------------------------------- |
| 2935 | 3051 |
| 2936 // Load the function. | 3052 // Load the function. |
| 2937 Load(function); | 3053 Load(function); |
| 3054 frame_->SpillAll(); | |
| 2938 | 3055 |
| 2939 // Pass the global proxy as the receiver. | 3056 // Pass the global proxy as the receiver. |
| 2940 LoadGlobalReceiver(eax); | 3057 LoadGlobalReceiver(eax); |
| 2941 | 3058 |
| 2942 // Call the function. | 3059 // Call the function. |
| 2943 CallWithArguments(args, node->position()); | 3060 CallWithArguments(args, node->position()); |
| 2944 } | 3061 } |
| 2945 } | 3062 } |
| 2946 | 3063 |
| 2947 | 3064 |
| 2948 void CodeGenerator::VisitCallNew(CallNew* node) { | 3065 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 2949 frame_->SpillAll(); | 3066 frame_->SpillAll(); |
| 2950 Comment cmnt(masm_, "[ CallNew"); | 3067 Comment cmnt(masm_, "[ CallNew"); |
| 2951 | 3068 |
| 2952 // According to ECMA-262, section 11.2.2, page 44, the function | 3069 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2953 // expression in new calls must be evaluated before the | 3070 // expression in new calls must be evaluated before the |
| 2954 // arguments. This is different from ordinary calls, where the | 3071 // arguments. This is different from ordinary calls, where the |
| 2955 // actual function to call is resolved after the arguments have been | 3072 // actual function to call is resolved after the arguments have been |
| 2956 // evaluated. | 3073 // evaluated. |
| 2957 | 3074 |
| 2958 // Compute function to call and use the global object as the | 3075 // Compute function to call and use the global object as the |
| 2959 // receiver. There is no need to use the global proxy here because | 3076 // receiver. There is no need to use the global proxy here because |
| 2960 // it will always be replaced with a newly allocated object. | 3077 // it will always be replaced with a newly allocated object. |
| 2961 Load(node->expression()); | 3078 Load(node->expression()); |
| 3079 frame_->SpillAll(); | |
| 2962 LoadGlobal(); | 3080 LoadGlobal(); |
| 2963 | 3081 |
| 2964 // Push the arguments ("left-to-right") on the stack. | 3082 // Push the arguments ("left-to-right") on the stack. |
| 2965 ZoneList<Expression*>* args = node->arguments(); | 3083 ZoneList<Expression*>* args = node->arguments(); |
| 2966 int arg_count = args->length(); | 3084 int arg_count = args->length(); |
| 2967 for (int i = 0; i < arg_count; i++) { | 3085 for (int i = 0; i < arg_count; i++) { |
| 2968 Load(args->at(i)); | 3086 Load(args->at(i)); |
| 3087 frame_->SpillAll(); | |
| 2969 } | 3088 } |
| 2970 | 3089 |
| 2971 // Constructors are called with the number of arguments in register | 3090 // Constructors are called with the number of arguments in register |
| 2972 // eax for now. Another option would be to have separate construct | 3091 // eax for now. Another option would be to have separate construct |
| 2973 // call trampolines per different arguments counts encountered. | 3092 // call trampolines per different arguments counts encountered. |
| 2974 __ Set(eax, Immediate(arg_count)); | 3093 __ Set(eax, Immediate(arg_count)); |
| 2975 | 3094 |
| 2976 // Load the function into temporary function slot as per calling | 3095 // Load the function into temporary function slot as per calling |
| 2977 // convention. | 3096 // convention. |
| 2978 __ mov(edi, frame_->ElementAt(arg_count + 1)); | 3097 __ mov(edi, frame_->ElementAt(arg_count + 1)); |
| 2979 | 3098 |
| 2980 // Call the construct call builtin that handles allocation and | 3099 // Call the construct call builtin that handles allocation and |
| 2981 // constructor invocation. | 3100 // constructor invocation. |
| 2982 __ RecordPosition(node->position()); | 3101 __ RecordPosition(node->position()); |
| 2983 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 3102 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
| 2984 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); | 3103 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); |
| 2985 // Discard the function and "push" the newly created object. | 3104 // Discard the function and "push" the newly created object. |
| 2986 __ mov(frame_->Top(), eax); | 3105 __ mov(frame_->Top(), eax); |
| 2987 } | 3106 } |
| 2988 | 3107 |
| 2989 | 3108 |
| 2990 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 3109 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 2991 ASSERT(args->length() == 1); | 3110 ASSERT(args->length() == 1); |
| 2992 Load(args->at(0)); | 3111 Load(args->at(0)); |
| 3112 frame_->SpillAll(); | |
|
iposva
2008/12/03 07:04:40
Is there a single call to Load in this file that i
Kevin Millikin (Chromium)
2008/12/03 15:08:38
Actually there are two (but they are easy to miss)
| |
| 2993 frame_->EmitPop(eax); | 3113 frame_->EmitPop(eax); |
| 2994 __ test(eax, Immediate(kSmiTagMask)); | 3114 __ test(eax, Immediate(kSmiTagMask)); |
| 2995 cc_reg_ = zero; | 3115 cc_reg_ = zero; |
| 2996 } | 3116 } |
| 2997 | 3117 |
| 2998 | 3118 |
| 2999 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3119 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 3000 ASSERT(args->length() == 1); | 3120 ASSERT(args->length() == 1); |
| 3001 Load(args->at(0)); | 3121 Load(args->at(0)); |
| 3122 frame_->SpillAll(); | |
| 3002 frame_->EmitPop(eax); | 3123 frame_->EmitPop(eax); |
| 3003 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); | 3124 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 3004 cc_reg_ = zero; | 3125 cc_reg_ = zero; |
| 3005 } | 3126 } |
| 3006 | 3127 |
| 3007 | 3128 |
| 3008 // This generates code that performs a charCodeAt() call or returns | 3129 // This generates code that performs a charCodeAt() call or returns |
| 3009 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3130 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 3010 // It can handle flat and sliced strings, 8 and 16 bit characters and | 3131 // It can handle flat and sliced strings, 8 and 16 bit characters and |
| 3011 // cons strings where the answer is found in the left hand branch of the | 3132 // cons strings where the answer is found in the left hand branch of the |
| 3012 // cons. The slow case will flatten the string, which will ensure that | 3133 // cons. The slow case will flatten the string, which will ensure that |
| 3013 // the answer is in the left hand side the next time around. | 3134 // the answer is in the left hand side the next time around. |
| 3014 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3135 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 3015 ASSERT(args->length() == 2); | 3136 ASSERT(args->length() == 2); |
| 3016 | 3137 |
| 3017 JumpTarget slow_case(this); | 3138 JumpTarget slow_case(this); |
| 3018 JumpTarget end(this); | 3139 JumpTarget end(this); |
| 3019 JumpTarget not_a_flat_string(this); | 3140 JumpTarget not_a_flat_string(this); |
| 3020 JumpTarget not_a_cons_string_either(this); | 3141 JumpTarget not_a_cons_string_either(this); |
| 3021 JumpTarget try_again_with_new_string(this); | 3142 JumpTarget try_again_with_new_string(this); |
| 3022 JumpTarget ascii_string(this); | 3143 JumpTarget ascii_string(this); |
| 3023 JumpTarget got_char_code(this); | 3144 JumpTarget got_char_code(this); |
| 3024 | 3145 |
| 3025 // Load the string into eax. | 3146 // Load the string into eax. |
| 3026 Load(args->at(0)); | 3147 Load(args->at(0)); |
| 3148 frame_->SpillAll(); | |
| 3027 frame_->EmitPop(eax); | 3149 frame_->EmitPop(eax); |
| 3028 // If the receiver is a smi return undefined. | 3150 // If the receiver is a smi return undefined. |
| 3029 ASSERT(kSmiTag == 0); | 3151 ASSERT(kSmiTag == 0); |
| 3030 __ test(eax, Immediate(kSmiTagMask)); | 3152 __ test(eax, Immediate(kSmiTagMask)); |
| 3031 slow_case.Branch(zero, not_taken); | 3153 slow_case.Branch(zero, not_taken); |
| 3032 | 3154 |
| 3033 // Load the index into ebx. | 3155 // Load the index into ebx. |
| 3034 Load(args->at(1)); | 3156 Load(args->at(1)); |
| 3157 frame_->SpillAll(); | |
| 3035 frame_->EmitPop(ebx); | 3158 frame_->EmitPop(ebx); |
| 3036 | 3159 |
| 3037 // Check for negative or non-smi index. | 3160 // Check for negative or non-smi index. |
| 3038 ASSERT(kSmiTag == 0); | 3161 ASSERT(kSmiTag == 0); |
| 3039 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); | 3162 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); |
| 3040 slow_case.Branch(not_zero, not_taken); | 3163 slow_case.Branch(not_zero, not_taken); |
| 3041 // Get rid of the smi tag on the index. | 3164 // Get rid of the smi tag on the index. |
| 3042 __ sar(ebx, kSmiTagSize); | 3165 __ sar(ebx, kSmiTagSize); |
| 3043 | 3166 |
| 3044 try_again_with_new_string.Bind(); | 3167 try_again_with_new_string.Bind(); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3120 slow_case.Bind(); | 3243 slow_case.Bind(); |
| 3121 frame_->EmitPush(Immediate(Factory::undefined_value())); | 3244 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3122 | 3245 |
| 3123 end.Bind(); | 3246 end.Bind(); |
| 3124 } | 3247 } |
| 3125 | 3248 |
| 3126 | 3249 |
| 3127 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3250 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3128 ASSERT(args->length() == 1); | 3251 ASSERT(args->length() == 1); |
| 3129 Load(args->at(0)); | 3252 Load(args->at(0)); |
| 3253 frame_->SpillAll(); | |
| 3130 JumpTarget answer(this); | 3254 JumpTarget answer(this); |
| 3131 // We need the CC bits to come out as not_equal in the case where the | 3255 // We need the CC bits to come out as not_equal in the case where the |
| 3132 // object is a smi. This can't be done with the usual test opcode so | 3256 // object is a smi. This can't be done with the usual test opcode so |
| 3133 // we copy the object to ecx and do some destructive ops on it that | 3257 // we copy the object to ecx and do some destructive ops on it that |
| 3134 // result in the right CC bits. | 3258 // result in the right CC bits. |
| 3135 frame_->EmitPop(eax); | 3259 frame_->EmitPop(eax); |
| 3136 __ mov(ecx, Operand(eax)); | 3260 __ mov(ecx, Operand(eax)); |
| 3137 __ and_(ecx, kSmiTagMask); | 3261 __ and_(ecx, kSmiTagMask); |
| 3138 __ xor_(ecx, kSmiTagMask); | 3262 __ xor_(ecx, kSmiTagMask); |
| 3139 answer.Branch(not_equal, not_taken); | 3263 answer.Branch(not_equal, not_taken); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 3159 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 3283 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 3160 frame_->CallStub(&stub, 0); | 3284 frame_->CallStub(&stub, 0); |
| 3161 frame_->EmitPush(eax); | 3285 frame_->EmitPush(eax); |
| 3162 } | 3286 } |
| 3163 | 3287 |
| 3164 | 3288 |
| 3165 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3289 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 3166 ASSERT(args->length() == 1); | 3290 ASSERT(args->length() == 1); |
| 3167 JumpTarget leave(this); | 3291 JumpTarget leave(this); |
| 3168 Load(args->at(0)); // Load the object. | 3292 Load(args->at(0)); // Load the object. |
| 3293 frame_->SpillAll(); | |
| 3169 __ mov(eax, frame_->Top()); | 3294 __ mov(eax, frame_->Top()); |
| 3170 // if (object->IsSmi()) return object. | 3295 // if (object->IsSmi()) return object. |
| 3171 __ test(eax, Immediate(kSmiTagMask)); | 3296 __ test(eax, Immediate(kSmiTagMask)); |
| 3172 leave.Branch(zero, taken); | 3297 leave.Branch(zero, taken); |
| 3173 // It is a heap object - get map. | 3298 // It is a heap object - get map. |
| 3174 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 3299 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3175 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 3300 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 3176 // if (!object->IsJSValue()) return object. | 3301 // if (!object->IsJSValue()) return object. |
| 3177 __ cmp(ecx, JS_VALUE_TYPE); | 3302 __ cmp(ecx, JS_VALUE_TYPE); |
| 3178 leave.Branch(not_equal, not_taken); | 3303 leave.Branch(not_equal, not_taken); |
| 3179 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 3304 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 3180 __ mov(frame_->Top(), eax); | 3305 __ mov(frame_->Top(), eax); |
| 3181 leave.Bind(); | 3306 leave.Bind(); |
| 3182 } | 3307 } |
| 3183 | 3308 |
| 3184 | 3309 |
| 3185 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 3310 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 3186 ASSERT(args->length() == 2); | 3311 ASSERT(args->length() == 2); |
| 3187 JumpTarget leave(this); | 3312 JumpTarget leave(this); |
| 3188 Load(args->at(0)); // Load the object. | 3313 Load(args->at(0)); // Load the object. |
| 3314 frame_->SpillAll(); | |
| 3189 Load(args->at(1)); // Load the value. | 3315 Load(args->at(1)); // Load the value. |
| 3316 frame_->SpillAll(); | |
| 3190 __ mov(eax, frame_->ElementAt(1)); | 3317 __ mov(eax, frame_->ElementAt(1)); |
| 3191 __ mov(ecx, frame_->Top()); | 3318 __ mov(ecx, frame_->Top()); |
| 3192 // if (object->IsSmi()) return object. | 3319 // if (object->IsSmi()) return object. |
| 3193 __ test(eax, Immediate(kSmiTagMask)); | 3320 __ test(eax, Immediate(kSmiTagMask)); |
| 3194 leave.Branch(zero, taken); | 3321 leave.Branch(zero, taken); |
| 3195 // It is a heap object - get map. | 3322 // It is a heap object - get map. |
| 3196 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 3323 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3197 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 3324 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 3198 // if (!object->IsJSValue()) return object. | 3325 // if (!object->IsJSValue()) return object. |
| 3199 __ cmp(ebx, JS_VALUE_TYPE); | 3326 __ cmp(ebx, JS_VALUE_TYPE); |
| 3200 leave.Branch(not_equal, not_taken); | 3327 leave.Branch(not_equal, not_taken); |
| 3201 // Store the value. | 3328 // Store the value. |
| 3202 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); | 3329 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); |
| 3203 // Update the write barrier. | 3330 // Update the write barrier. |
| 3204 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); | 3331 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); |
| 3205 // Leave. | 3332 // Leave. |
| 3206 leave.Bind(); | 3333 leave.Bind(); |
| 3207 __ mov(ecx, frame_->Top()); | 3334 __ mov(ecx, frame_->Top()); |
| 3208 frame_->Drop(); | 3335 frame_->Drop(); |
| 3209 __ mov(frame_->Top(), ecx); | 3336 __ mov(frame_->Top(), ecx); |
| 3210 } | 3337 } |
| 3211 | 3338 |
| 3212 | 3339 |
| 3213 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3340 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 3214 ASSERT(args->length() == 1); | 3341 ASSERT(args->length() == 1); |
| 3215 | 3342 |
| 3216 // Load the key onto the stack and set register eax to the formal | 3343 // Load the key onto the stack and set register eax to the formal |
| 3217 // parameters count for the currently executing function. | 3344 // parameters count for the currently executing function. |
| 3218 Load(args->at(0)); | 3345 Load(args->at(0)); |
| 3346 frame_->SpillAll(); | |
| 3219 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3347 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 3220 | 3348 |
| 3221 // Call the shared stub to get to arguments[key]. | 3349 // Call the shared stub to get to arguments[key]. |
| 3222 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 3350 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 3223 frame_->CallStub(&stub, 0); | 3351 frame_->CallStub(&stub, 0); |
| 3224 __ mov(frame_->Top(), eax); | 3352 __ mov(frame_->Top(), eax); |
| 3225 } | 3353 } |
| 3226 | 3354 |
| 3227 | 3355 |
| 3228 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 3356 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 3229 ASSERT(args->length() == 2); | 3357 ASSERT(args->length() == 2); |
| 3230 | 3358 |
| 3231 // Load the two objects into registers and perform the comparison. | 3359 // Load the two objects into registers and perform the comparison. |
| 3232 Load(args->at(0)); | 3360 Load(args->at(0)); |
| 3361 frame_->SpillAll(); | |
| 3233 Load(args->at(1)); | 3362 Load(args->at(1)); |
| 3363 frame_->SpillAll(); | |
| 3234 frame_->EmitPop(eax); | 3364 frame_->EmitPop(eax); |
| 3235 frame_->EmitPop(ecx); | 3365 frame_->EmitPop(ecx); |
| 3236 __ cmp(eax, Operand(ecx)); | 3366 __ cmp(eax, Operand(ecx)); |
| 3237 cc_reg_ = equal; | 3367 cc_reg_ = equal; |
| 3238 } | 3368 } |
| 3239 | 3369 |
| 3240 | 3370 |
| 3241 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 3371 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 3242 frame_->SpillAll(); | 3372 frame_->SpillAll(); |
| 3243 if (CheckForInlineRuntimeCall(node)) { | 3373 if (CheckForInlineRuntimeCall(node)) { |
| 3244 return; | 3374 return; |
| 3245 } | 3375 } |
| 3246 | 3376 |
| 3247 ZoneList<Expression*>* args = node->arguments(); | 3377 ZoneList<Expression*>* args = node->arguments(); |
| 3248 Comment cmnt(masm_, "[ CallRuntime"); | 3378 Comment cmnt(masm_, "[ CallRuntime"); |
| 3249 Runtime::Function* function = node->function(); | 3379 Runtime::Function* function = node->function(); |
| 3250 | 3380 |
| 3251 if (function == NULL) { | 3381 if (function == NULL) { |
| 3252 // Prepare stack for calling JS runtime function. | 3382 // Prepare stack for calling JS runtime function. |
| 3253 frame_->EmitPush(Immediate(node->name())); | 3383 frame_->EmitPush(Immediate(node->name())); |
| 3254 // Push the builtins object found in the current global object. | 3384 // Push the builtins object found in the current global object. |
| 3255 __ mov(edx, GlobalObject()); | 3385 __ mov(edx, GlobalObject()); |
| 3256 frame_->EmitPush(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); | 3386 frame_->EmitPush(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); |
| 3257 } | 3387 } |
| 3258 | 3388 |
| 3259 // Push the arguments ("left-to-right"). | 3389 // Push the arguments ("left-to-right"). |
| 3260 int arg_count = args->length(); | 3390 int arg_count = args->length(); |
| 3261 for (int i = 0; i < arg_count; i++) { | 3391 for (int i = 0; i < arg_count; i++) { |
| 3262 Load(args->at(i)); | 3392 Load(args->at(i)); |
| 3393 frame_->SpillAll(); | |
| 3263 } | 3394 } |
| 3264 | 3395 |
| 3265 if (function == NULL) { | 3396 if (function == NULL) { |
| 3266 // Call the JS runtime function. | 3397 // Call the JS runtime function. |
| 3267 Handle<Code> stub = ComputeCallInitialize(arg_count); | 3398 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 3268 __ Set(eax, Immediate(args->length())); | 3399 __ Set(eax, Immediate(args->length())); |
| 3269 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); | 3400 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 3270 __ mov(esi, frame_->Context()); | 3401 __ mov(esi, frame_->Context()); |
| 3271 __ mov(frame_->Top(), eax); | 3402 __ mov(frame_->Top(), eax); |
| 3272 } else { | 3403 } else { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 3288 | 3419 |
| 3289 if (op == Token::NOT) { | 3420 if (op == Token::NOT) { |
| 3290 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, | 3421 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
| 3291 false_target(), true_target(), true); | 3422 false_target(), true_target(), true); |
| 3292 cc_reg_ = NegateCondition(cc_reg_); | 3423 cc_reg_ = NegateCondition(cc_reg_); |
| 3293 | 3424 |
| 3294 } else if (op == Token::DELETE) { | 3425 } else if (op == Token::DELETE) { |
| 3295 Property* property = node->expression()->AsProperty(); | 3426 Property* property = node->expression()->AsProperty(); |
| 3296 if (property != NULL) { | 3427 if (property != NULL) { |
| 3297 Load(property->obj()); | 3428 Load(property->obj()); |
| 3429 frame_->SpillAll(); | |
| 3298 Load(property->key()); | 3430 Load(property->key()); |
| 3431 frame_->SpillAll(); | |
| 3299 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3432 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3300 frame_->EmitPush(eax); | 3433 frame_->EmitPush(eax); |
| 3301 return; | 3434 return; |
| 3302 } | 3435 } |
| 3303 | 3436 |
| 3304 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 3437 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 3305 if (variable != NULL) { | 3438 if (variable != NULL) { |
| 3306 Slot* slot = variable->slot(); | 3439 Slot* slot = variable->slot(); |
| 3307 if (variable->is_global()) { | 3440 if (variable->is_global()) { |
| 3308 LoadGlobal(); | 3441 LoadGlobal(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 3324 return; | 3457 return; |
| 3325 } | 3458 } |
| 3326 | 3459 |
| 3327 // Default: Result of deleting non-global, not dynamically | 3460 // Default: Result of deleting non-global, not dynamically |
| 3328 // introduced variables is false. | 3461 // introduced variables is false. |
| 3329 frame_->EmitPush(Immediate(Factory::false_value())); | 3462 frame_->EmitPush(Immediate(Factory::false_value())); |
| 3330 | 3463 |
| 3331 } else { | 3464 } else { |
| 3332 // Default: Result of deleting expressions is true. | 3465 // Default: Result of deleting expressions is true. |
| 3333 Load(node->expression()); // may have side-effects | 3466 Load(node->expression()); // may have side-effects |
| 3467 frame_->SpillAll(); | |
| 3334 __ Set(frame_->Top(), Immediate(Factory::true_value())); | 3468 __ Set(frame_->Top(), Immediate(Factory::true_value())); |
| 3335 } | 3469 } |
| 3336 | 3470 |
| 3337 } else if (op == Token::TYPEOF) { | 3471 } else if (op == Token::TYPEOF) { |
| 3338 // Special case for loading the typeof expression; see comment on | 3472 // Special case for loading the typeof expression; see comment on |
| 3339 // LoadTypeofExpression(). | 3473 // LoadTypeofExpression(). |
| 3340 LoadTypeofExpression(node->expression()); | 3474 LoadTypeofExpression(node->expression()); |
| 3341 frame_->CallRuntime(Runtime::kTypeof, 1); | 3475 frame_->CallRuntime(Runtime::kTypeof, 1); |
| 3342 frame_->EmitPush(eax); | 3476 frame_->EmitPush(eax); |
| 3343 | 3477 |
| 3344 } else { | 3478 } else { |
| 3345 Load(node->expression()); | 3479 Load(node->expression()); |
| 3480 frame_->SpillAll(); | |
| 3346 switch (op) { | 3481 switch (op) { |
| 3347 case Token::NOT: | 3482 case Token::NOT: |
| 3348 case Token::DELETE: | 3483 case Token::DELETE: |
| 3349 case Token::TYPEOF: | 3484 case Token::TYPEOF: |
| 3350 UNREACHABLE(); // handled above | 3485 UNREACHABLE(); // handled above |
| 3351 break; | 3486 break; |
| 3352 | 3487 |
| 3353 case Token::SUB: { | 3488 case Token::SUB: { |
| 3354 UnarySubStub stub; | 3489 UnarySubStub stub; |
| 3355 // TODO(1222589): remove dependency of TOS being cached inside stub | 3490 // TODO(1222589): remove dependency of TOS being cached inside stub |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3584 Branch(false, false_target()); | 3719 Branch(false, false_target()); |
| 3585 } | 3720 } |
| 3586 | 3721 |
| 3587 if (frame_ != NULL || is_true.is_linked()) { | 3722 if (frame_ != NULL || is_true.is_linked()) { |
| 3588 // Evaluate right side expression. | 3723 // Evaluate right side expression. |
| 3589 is_true.Bind(); | 3724 is_true.Bind(); |
| 3590 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), | 3725 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), |
| 3591 false_target(), false); | 3726 false_target(), false); |
| 3592 } | 3727 } |
| 3593 } else { | 3728 } else { |
| 3729 frame_->SpillAll(); | |
| 3594 // We have a materialized value on the frame. | 3730 // We have a materialized value on the frame. |
| 3595 JumpTarget pop_and_continue(this); | 3731 JumpTarget pop_and_continue(this); |
| 3596 JumpTarget exit(this); | 3732 JumpTarget exit(this); |
| 3597 | 3733 |
| 3598 // Avoid popping the result if it converts to 'false' using the | 3734 // Avoid popping the result if it converts to 'false' using the |
| 3599 // standard ToBoolean() conversion as described in ECMA-262, section | 3735 // standard ToBoolean() conversion as described in ECMA-262, section |
| 3600 // 9.2, page 30. | 3736 // 9.2, page 30. |
| 3601 // | 3737 // |
| 3602 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3738 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3603 __ mov(eax, frame_->Top()); | 3739 __ mov(eax, frame_->Top()); |
| 3604 frame_->EmitPush(eax); | 3740 frame_->EmitPush(eax); |
| 3605 ToBoolean(&pop_and_continue, &exit); | 3741 ToBoolean(&pop_and_continue, &exit); |
| 3606 Branch(false, &exit); | 3742 Branch(false, &exit); |
| 3607 | 3743 |
| 3608 // Pop the result of evaluating the first part. | 3744 // Pop the result of evaluating the first part. |
| 3609 pop_and_continue.Bind(); | 3745 pop_and_continue.Bind(); |
| 3610 frame_->Drop(); | 3746 frame_->Drop(); |
| 3611 | 3747 |
| 3612 // Evaluate right side expression. | 3748 // Evaluate right side expression. |
| 3613 is_true.Bind(); | 3749 is_true.Bind(); |
| 3614 Load(node->right()); | 3750 Load(node->right()); |
| 3751 frame_->SpillAll(); | |
| 3615 | 3752 |
| 3616 // Exit (always with a materialized value). | 3753 // Exit (always with a materialized value). |
| 3617 exit.Bind(); | 3754 exit.Bind(); |
| 3618 } | 3755 } |
| 3619 | 3756 |
| 3620 } else if (op == Token::OR) { | 3757 } else if (op == Token::OR) { |
| 3621 JumpTarget is_false(this); | 3758 JumpTarget is_false(this); |
| 3622 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), | 3759 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), |
| 3623 &is_false, false); | 3760 &is_false, false); |
| 3624 if (has_cc() || frame_ == NULL) { | 3761 if (has_cc() || frame_ == NULL) { |
| 3625 if (has_cc()) { | 3762 if (has_cc()) { |
| 3626 ASSERT(frame_ != NULL); | 3763 ASSERT(frame_ != NULL); |
| 3627 Branch(true, true_target()); | 3764 Branch(true, true_target()); |
| 3628 } | 3765 } |
| 3629 | 3766 |
| 3630 if (frame_ != NULL || is_false.is_linked()) { | 3767 if (frame_ != NULL || is_false.is_linked()) { |
| 3631 // Evaluate right side expression. | 3768 // Evaluate right side expression. |
| 3632 is_false.Bind(); | 3769 is_false.Bind(); |
| 3633 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), | 3770 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), |
| 3634 false_target(), false); | 3771 false_target(), false); |
| 3635 } | 3772 } |
| 3636 | 3773 |
| 3637 } else { | 3774 } else { |
| 3775 frame_->SpillAll(); | |
| 3638 // We have a materialized value on the frame. | 3776 // We have a materialized value on the frame. |
| 3639 JumpTarget pop_and_continue(this); | 3777 JumpTarget pop_and_continue(this); |
| 3640 JumpTarget exit(this); | 3778 JumpTarget exit(this); |
| 3641 | 3779 |
| 3642 // Avoid popping the result if it converts to 'true' using the | 3780 // Avoid popping the result if it converts to 'true' using the |
| 3643 // standard ToBoolean() conversion as described in ECMA-262, | 3781 // standard ToBoolean() conversion as described in ECMA-262, |
| 3644 // section 9.2, page 30. | 3782 // section 9.2, page 30. |
| 3645 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3783 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3646 __ mov(eax, frame_->Top()); | 3784 __ mov(eax, frame_->Top()); |
| 3647 frame_->EmitPush(eax); | 3785 frame_->EmitPush(eax); |
| 3648 ToBoolean(&exit, &pop_and_continue); | 3786 ToBoolean(&exit, &pop_and_continue); |
| 3649 Branch(true, &exit); | 3787 Branch(true, &exit); |
| 3650 | 3788 |
| 3651 // Pop the result of evaluating the first part. | 3789 // Pop the result of evaluating the first part. |
| 3652 pop_and_continue.Bind(); | 3790 pop_and_continue.Bind(); |
| 3653 frame_->Drop(); | 3791 frame_->Drop(); |
| 3654 | 3792 |
| 3655 // Evaluate right side expression. | 3793 // Evaluate right side expression. |
| 3656 is_false.Bind(); | 3794 is_false.Bind(); |
| 3657 Load(node->right()); | 3795 Load(node->right()); |
| 3796 frame_->SpillAll(); | |
| 3658 | 3797 |
| 3659 // Exit (always with a materialized value). | 3798 // Exit (always with a materialized value). |
| 3660 exit.Bind(); | 3799 exit.Bind(); |
| 3661 } | 3800 } |
| 3662 | 3801 |
| 3663 } else { | 3802 } else { |
| 3664 // NOTE: The code below assumes that the slow cases (calls to runtime) | 3803 // NOTE: The code below assumes that the slow cases (calls to runtime) |
| 3665 // never return a constant/immutable object. | 3804 // never return a constant/immutable object. |
| 3666 OverwriteMode overwrite_mode = NO_OVERWRITE; | 3805 OverwriteMode overwrite_mode = NO_OVERWRITE; |
| 3667 if (node->left()->AsBinaryOperation() != NULL && | 3806 if (node->left()->AsBinaryOperation() != NULL && |
| 3668 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 3807 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 3669 overwrite_mode = OVERWRITE_LEFT; | 3808 overwrite_mode = OVERWRITE_LEFT; |
| 3670 } else if (node->right()->AsBinaryOperation() != NULL && | 3809 } else if (node->right()->AsBinaryOperation() != NULL && |
| 3671 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 3810 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 3672 overwrite_mode = OVERWRITE_RIGHT; | 3811 overwrite_mode = OVERWRITE_RIGHT; |
| 3673 } | 3812 } |
| 3674 | 3813 |
| 3675 // Optimize for the case where (at least) one of the expressions | 3814 // Optimize for the case where (at least) one of the expressions |
| 3676 // is a literal small integer. | 3815 // is a literal small integer. |
| 3677 Literal* lliteral = node->left()->AsLiteral(); | 3816 Literal* lliteral = node->left()->AsLiteral(); |
| 3678 Literal* rliteral = node->right()->AsLiteral(); | 3817 Literal* rliteral = node->right()->AsLiteral(); |
| 3679 | 3818 |
| 3680 if (IsInlineSmi(rliteral)) { | 3819 if (IsInlineSmi(rliteral)) { |
| 3681 Load(node->left()); | 3820 Load(node->left()); |
| 3821 frame_->SpillAll(); | |
| 3682 SmiOperation(node->op(), node->type(), rliteral->handle(), false, | 3822 SmiOperation(node->op(), node->type(), rliteral->handle(), false, |
| 3683 overwrite_mode); | 3823 overwrite_mode); |
| 3684 } else if (IsInlineSmi(lliteral)) { | 3824 } else if (IsInlineSmi(lliteral)) { |
| 3685 Load(node->right()); | 3825 Load(node->right()); |
| 3826 frame_->SpillAll(); | |
| 3686 SmiOperation(node->op(), node->type(), lliteral->handle(), true, | 3827 SmiOperation(node->op(), node->type(), lliteral->handle(), true, |
| 3687 overwrite_mode); | 3828 overwrite_mode); |
| 3688 } else { | 3829 } else { |
| 3689 Load(node->left()); | 3830 Load(node->left()); |
| 3831 frame_->SpillAll(); | |
| 3690 Load(node->right()); | 3832 Load(node->right()); |
| 3833 frame_->SpillAll(); | |
| 3691 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); | 3834 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
| 3692 } | 3835 } |
| 3693 } | 3836 } |
| 3694 } | 3837 } |
| 3695 | 3838 |
| 3696 | 3839 |
| 3697 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3840 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3698 frame_->SpillAll(); | 3841 frame_->SpillAll(); |
| 3699 frame_->EmitPush(frame_->Function()); | 3842 frame_->EmitPush(frame_->Function()); |
| 3700 } | 3843 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 3726 // instead of calling the (very) general runtime routine for checking | 3869 // instead of calling the (very) general runtime routine for checking |
| 3727 // equality. | 3870 // equality. |
| 3728 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3871 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3729 bool left_is_null = | 3872 bool left_is_null = |
| 3730 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3873 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3731 bool right_is_null = | 3874 bool right_is_null = |
| 3732 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3875 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 3733 // The 'null' value can only be equal to 'null' or 'undefined'. | 3876 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 3734 if (left_is_null || right_is_null) { | 3877 if (left_is_null || right_is_null) { |
| 3735 Load(left_is_null ? right : left); | 3878 Load(left_is_null ? right : left); |
| 3879 frame_->SpillAll(); | |
| 3736 frame_->EmitPop(eax); | 3880 frame_->EmitPop(eax); |
| 3737 __ cmp(eax, Factory::null_value()); | 3881 __ cmp(eax, Factory::null_value()); |
| 3738 | 3882 |
| 3739 // The 'null' value is only equal to 'undefined' if using non-strict | 3883 // The 'null' value is only equal to 'undefined' if using non-strict |
| 3740 // comparisons. | 3884 // comparisons. |
| 3741 if (op != Token::EQ_STRICT) { | 3885 if (op != Token::EQ_STRICT) { |
| 3742 true_target()->Branch(equal); | 3886 true_target()->Branch(equal); |
| 3743 | 3887 |
| 3744 __ cmp(eax, Factory::undefined_value()); | 3888 __ cmp(eax, Factory::undefined_value()); |
| 3745 true_target()->Branch(equal); | 3889 true_target()->Branch(equal); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3871 cc = greater; | 4015 cc = greater; |
| 3872 break; | 4016 break; |
| 3873 case Token::LTE: | 4017 case Token::LTE: |
| 3874 cc = less_equal; | 4018 cc = less_equal; |
| 3875 break; | 4019 break; |
| 3876 case Token::GTE: | 4020 case Token::GTE: |
| 3877 cc = greater_equal; | 4021 cc = greater_equal; |
| 3878 break; | 4022 break; |
| 3879 case Token::IN: { | 4023 case Token::IN: { |
| 3880 Load(left); | 4024 Load(left); |
| 4025 frame_->SpillAll(); | |
| 3881 Load(right); | 4026 Load(right); |
| 4027 frame_->SpillAll(); | |
| 3882 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); | 4028 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); |
| 3883 frame_->EmitPush(eax); // push the result | 4029 frame_->EmitPush(eax); // push the result |
| 3884 return; | 4030 return; |
| 3885 } | 4031 } |
| 3886 case Token::INSTANCEOF: { | 4032 case Token::INSTANCEOF: { |
| 3887 Load(left); | 4033 Load(left); |
| 4034 frame_->SpillAll(); | |
| 3888 Load(right); | 4035 Load(right); |
| 4036 frame_->SpillAll(); | |
| 3889 InstanceofStub stub; | 4037 InstanceofStub stub; |
| 3890 frame_->CallStub(&stub, 2); | 4038 frame_->CallStub(&stub, 2); |
| 3891 __ test(eax, Operand(eax)); | 4039 __ test(eax, Operand(eax)); |
| 3892 cc_reg_ = zero; | 4040 cc_reg_ = zero; |
| 3893 return; | 4041 return; |
| 3894 } | 4042 } |
| 3895 default: | 4043 default: |
| 3896 UNREACHABLE(); | 4044 UNREACHABLE(); |
| 3897 } | 4045 } |
| 3898 | 4046 |
| 3899 // Optimize for the case where (at least) one of the expressions | 4047 // Optimize for the case where (at least) one of the expressions |
| 3900 // is a literal small integer. | 4048 // is a literal small integer. |
| 3901 if (IsInlineSmi(left->AsLiteral())) { | 4049 if (IsInlineSmi(left->AsLiteral())) { |
| 3902 Load(right); | 4050 Load(right); |
| 4051 frame_->SpillAll(); | |
| 3903 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict); | 4052 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict); |
| 3904 return; | 4053 return; |
| 3905 } | 4054 } |
| 3906 if (IsInlineSmi(right->AsLiteral())) { | 4055 if (IsInlineSmi(right->AsLiteral())) { |
| 3907 Load(left); | 4056 Load(left); |
| 4057 frame_->SpillAll(); | |
| 3908 SmiComparison(cc, right->AsLiteral()->handle(), strict); | 4058 SmiComparison(cc, right->AsLiteral()->handle(), strict); |
| 3909 return; | 4059 return; |
| 3910 } | 4060 } |
| 3911 | 4061 |
| 3912 Load(left); | 4062 Load(left); |
| 4063 frame_->SpillAll(); | |
| 3913 Load(right); | 4064 Load(right); |
| 4065 frame_->SpillAll(); | |
| 3914 Comparison(cc, strict); | 4066 Comparison(cc, strict); |
| 3915 } | 4067 } |
| 3916 | 4068 |
| 3917 | 4069 |
| 3918 void CodeGenerator::RecordStatementPosition(Node* node) { | 4070 void CodeGenerator::RecordStatementPosition(Node* node) { |
| 3919 if (FLAG_debug_info) { | 4071 if (FLAG_debug_info) { |
| 3920 int pos = node->statement_pos(); | 4072 int pos = node->statement_pos(); |
| 3921 if (pos != RelocInfo::kNoPosition) { | 4073 if (pos != RelocInfo::kNoPosition) { |
| 3922 __ RecordStatementPosition(pos); | 4074 __ RecordStatementPosition(pos); |
| 3923 } | 4075 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4018 void Reference::SetValue(InitState init_state) { | 4170 void Reference::SetValue(InitState init_state) { |
| 4019 ASSERT(!is_illegal()); | 4171 ASSERT(!is_illegal()); |
| 4020 ASSERT(!cgen_->has_cc()); | 4172 ASSERT(!cgen_->has_cc()); |
| 4021 MacroAssembler* masm = cgen_->masm(); | 4173 MacroAssembler* masm = cgen_->masm(); |
| 4022 VirtualFrame* frame = cgen_->frame(); | 4174 VirtualFrame* frame = cgen_->frame(); |
| 4023 switch (type_) { | 4175 switch (type_) { |
| 4024 case SLOT: { | 4176 case SLOT: { |
| 4025 Comment cmnt(masm, "[ Store to Slot"); | 4177 Comment cmnt(masm, "[ Store to Slot"); |
| 4026 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4178 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 4027 ASSERT(slot != NULL); | 4179 ASSERT(slot != NULL); |
| 4028 if (slot->type() == Slot::LOOKUP) { | 4180 cgen_->StoreToSlot(slot, init_state); |
| 4029 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | |
| 4030 | |
| 4031 // For now, just do a runtime call. | |
| 4032 frame->EmitPush(esi); | |
| 4033 frame->EmitPush(Immediate(slot->var()->name())); | |
| 4034 | |
| 4035 if (init_state == CONST_INIT) { | |
| 4036 // Same as the case for a normal store, but ignores attribute | |
| 4037 // (e.g. READ_ONLY) of context slot so that we can initialize | |
| 4038 // const properties (introduced via eval("const foo = (some | |
| 4039 // expr);")). Also, uses the current function context instead of | |
| 4040 // the top context. | |
| 4041 // | |
| 4042 // Note that we must declare the foo upon entry of eval(), via a | |
| 4043 // context slot declaration, but we cannot initialize it at the | |
| 4044 // same time, because the const declaration may be at the end of | |
| 4045 // the eval code (sigh...) and the const variable may have been | |
| 4046 // used before (where its value is 'undefined'). Thus, we can only | |
| 4047 // do the initialization when we actually encounter the expression | |
| 4048 // and when the expression operands are defined and valid, and | |
| 4049 // thus we need the split into 2 operations: declaration of the | |
| 4050 // context slot followed by initialization. | |
| 4051 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
| 4052 } else { | |
| 4053 frame->CallRuntime(Runtime::kStoreContextSlot, 3); | |
| 4054 } | |
| 4055 // Storing a variable must keep the (new) value on the expression | |
| 4056 // stack. This is necessary for compiling chained assignment | |
| 4057 // expressions. | |
| 4058 frame->EmitPush(eax); | |
| 4059 | |
| 4060 } else { | |
| 4061 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | |
| 4062 | |
| 4063 JumpTarget exit(cgen_); | |
| 4064 if (init_state == CONST_INIT) { | |
| 4065 ASSERT(slot->var()->mode() == Variable::CONST); | |
| 4066 // Only the first const initialization must be executed (the slot | |
| 4067 // still contains 'the hole' value). When the assignment is | |
| 4068 // executed, the code is identical to a normal store (see below). | |
| 4069 Comment cmnt(masm, "[ Init const"); | |
| 4070 __ mov(eax, cgen_->SlotOperand(slot, ecx)); | |
| 4071 __ cmp(eax, Factory::the_hole_value()); | |
| 4072 exit.Branch(not_equal); | |
| 4073 } | |
| 4074 | |
| 4075 // We must execute the store. Storing a variable must keep the | |
| 4076 // (new) value on the stack. This is necessary for compiling | |
| 4077 // assignment expressions. | |
| 4078 // | |
| 4079 // Note: We will reach here even with slot->var()->mode() == | |
| 4080 // Variable::CONST because of const declarations which will | |
| 4081 // initialize consts to 'the hole' value and by doing so, end up | |
| 4082 // calling this code. | |
| 4083 frame->EmitPop(eax); | |
| 4084 __ mov(cgen_->SlotOperand(slot, ecx), eax); | |
| 4085 frame->EmitPush(eax); // RecordWrite may destroy the value in eax. | |
| 4086 if (slot->type() == Slot::CONTEXT) { | |
| 4087 // ecx is loaded with context when calling SlotOperand above. | |
| 4088 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
| 4089 __ RecordWrite(ecx, offset, eax, ebx); | |
| 4090 } | |
| 4091 // If we definitely did not jump over the assignment, we do not need | |
| 4092 // to bind the exit label. Doing so can defeat peephole | |
| 4093 // optimization. | |
| 4094 if (init_state == CONST_INIT) { | |
| 4095 exit.Bind(); | |
| 4096 } | |
| 4097 } | |
| 4098 break; | 4181 break; |
| 4099 } | 4182 } |
| 4100 | 4183 |
| 4101 case NAMED: { | 4184 case NAMED: { |
| 4185 frame->SpillAll(); | |
|
iposva
2008/12/03 07:04:40
Could this SpillAll() be moved after the EmitPop(e
Kevin Millikin (Chromium)
2008/12/03 15:08:38
Eventually when this code is reworked. Right now
| |
| 4102 Comment cmnt(masm, "[ Store to named Property"); | 4186 Comment cmnt(masm, "[ Store to named Property"); |
| 4103 // Call the appropriate IC code. | 4187 // Call the appropriate IC code. |
| 4104 Handle<String> name(GetName()); | 4188 Handle<String> name(GetName()); |
| 4105 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4189 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 4106 // TODO(1222589): Make the IC grab the values from the stack. | 4190 // TODO(1222589): Make the IC grab the values from the stack. |
| 4107 frame->EmitPop(eax); | 4191 frame->EmitPop(eax); |
| 4108 // Setup the name register. | 4192 // Setup the name register. |
| 4109 __ mov(ecx, name); | 4193 __ mov(ecx, name); |
| 4110 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4194 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4111 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4195 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4112 break; | 4196 break; |
| 4113 } | 4197 } |
| 4114 | 4198 |
| 4115 case KEYED: { | 4199 case KEYED: { |
| 4200 frame->SpillAll(); | |
|
iposva
2008/12/03 07:04:40
ditto.
| |
| 4116 Comment cmnt(masm, "[ Store to keyed Property"); | 4201 Comment cmnt(masm, "[ Store to keyed Property"); |
| 4117 Property* property = expression_->AsProperty(); | 4202 Property* property = expression_->AsProperty(); |
| 4118 ASSERT(property != NULL); | 4203 ASSERT(property != NULL); |
| 4119 __ RecordPosition(property->position()); | 4204 __ RecordPosition(property->position()); |
| 4120 // Call IC code. | 4205 // Call IC code. |
| 4121 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 4206 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 4122 // TODO(1222589): Make the IC grab the values from the stack. | 4207 // TODO(1222589): Make the IC grab the values from the stack. |
| 4123 frame->EmitPop(eax); | 4208 frame->EmitPop(eax); |
| 4124 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4209 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4125 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4210 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| (...skipping 1224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5350 | 5435 |
| 5351 // Slow-case: Go through the JavaScript implementation. | 5436 // Slow-case: Go through the JavaScript implementation. |
| 5352 __ bind(&slow); | 5437 __ bind(&slow); |
| 5353 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5438 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5354 } | 5439 } |
| 5355 | 5440 |
| 5356 | 5441 |
| 5357 #undef __ | 5442 #undef __ |
| 5358 | 5443 |
| 5359 } } // namespace v8::internal | 5444 } } // namespace v8::internal |
| OLD | NEW |