| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 129 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 130 frame_->SpillAll(); | 130 frame_->SpillAll(); |
| 131 __ stop("stop-at"); | 131 __ stop("stop-at"); |
| 132 } | 132 } |
| 133 #endif | 133 #endif |
| 134 | 134 |
| 135 // Allocate space for locals and initialize them. | 135 // Allocate space for locals and initialize them. |
| 136 frame_->AllocateStackSlots(scope_->num_stack_slots()); | 136 frame_->AllocateStackSlots(scope_->num_stack_slots()); |
| 137 // Initialize the function return target after the locals are set | 137 // Initialize the function return target after the locals are set |
| 138 // up, because it needs the expected frame height from the frame. | 138 // up, because it needs the expected frame height from the frame. |
| 139 function_return_.Initialize(this, JumpTarget::BIDIRECTIONAL); | 139 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
| 140 function_return_is_shadowed_ = false; | 140 function_return_is_shadowed_ = false; |
| 141 | 141 |
| 142 VirtualFrame::SpilledScope spilled_scope(this); | 142 VirtualFrame::SpilledScope spilled_scope(this); |
| 143 if (scope_->num_heap_slots() > 0) { | 143 if (scope_->num_heap_slots() > 0) { |
| 144 // Allocate local context. | 144 // Allocate local context. |
| 145 // Get outer context and create a new context based on it. | 145 // Get outer context and create a new context based on it. |
| 146 __ ldr(r0, frame_->Function()); | 146 __ ldr(r0, frame_->Function()); |
| 147 frame_->EmitPush(r0); | 147 frame_->EmitPush(r0); |
| 148 frame_->CallRuntime(Runtime::kNewContext, 1); // r0 holds the result | 148 frame_->CallRuntime(Runtime::kNewContext, 1); // r0 holds the result |
| 149 | 149 |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 frame_->SpillAll(); | 449 frame_->SpillAll(); |
| 450 set_in_spilled_code(true); | 450 set_in_spilled_code(true); |
| 451 } | 451 } |
| 452 | 452 |
| 453 | 453 |
| 454 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 454 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 455 #ifdef DEBUG | 455 #ifdef DEBUG |
| 456 int original_height = frame_->height(); | 456 int original_height = frame_->height(); |
| 457 #endif | 457 #endif |
| 458 ASSERT(!in_spilled_code()); | 458 ASSERT(!in_spilled_code()); |
| 459 JumpTarget true_target(this); | 459 JumpTarget true_target; |
| 460 JumpTarget false_target(this); | 460 JumpTarget false_target; |
| 461 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 461 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 462 | 462 |
| 463 if (has_cc()) { | 463 if (has_cc()) { |
| 464 // Convert cc_reg_ into a boolean value. | 464 // Convert cc_reg_ into a boolean value. |
| 465 JumpTarget loaded(this); | 465 JumpTarget loaded; |
| 466 JumpTarget materialize_true(this); | 466 JumpTarget materialize_true; |
| 467 materialize_true.Branch(cc_reg_); | 467 materialize_true.Branch(cc_reg_); |
| 468 __ mov(r0, Operand(Factory::false_value())); | 468 __ mov(r0, Operand(Factory::false_value())); |
| 469 frame_->EmitPush(r0); | 469 frame_->EmitPush(r0); |
| 470 loaded.Jump(); | 470 loaded.Jump(); |
| 471 materialize_true.Bind(); | 471 materialize_true.Bind(); |
| 472 __ mov(r0, Operand(Factory::true_value())); | 472 __ mov(r0, Operand(Factory::true_value())); |
| 473 frame_->EmitPush(r0); | 473 frame_->EmitPush(r0); |
| 474 loaded.Bind(); | 474 loaded.Bind(); |
| 475 cc_reg_ = al; | 475 cc_reg_ = al; |
| 476 } | 476 } |
| 477 | 477 |
| 478 if (true_target.is_linked() || false_target.is_linked()) { | 478 if (true_target.is_linked() || false_target.is_linked()) { |
| 479 // We have at least one condition value that has been "translated" | 479 // We have at least one condition value that has been "translated" |
| 480 // into a branch, thus it needs to be loaded explicitly. | 480 // into a branch, thus it needs to be loaded explicitly. |
| 481 JumpTarget loaded(this); | 481 JumpTarget loaded; |
| 482 if (frame_ != NULL) { | 482 if (frame_ != NULL) { |
| 483 loaded.Jump(); // Don't lose the current TOS. | 483 loaded.Jump(); // Don't lose the current TOS. |
| 484 } | 484 } |
| 485 bool both = true_target.is_linked() && false_target.is_linked(); | 485 bool both = true_target.is_linked() && false_target.is_linked(); |
| 486 // Load "true" if necessary. | 486 // Load "true" if necessary. |
| 487 if (true_target.is_linked()) { | 487 if (true_target.is_linked()) { |
| 488 true_target.Bind(); | 488 true_target.Bind(); |
| 489 __ mov(r0, Operand(Factory::true_value())); | 489 __ mov(r0, Operand(Factory::true_value())); |
| 490 frame_->EmitPush(r0); | 490 frame_->EmitPush(r0); |
| 491 } | 491 } |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 // some possible smi operations (like + and -) when (at least) one | 858 // some possible smi operations (like + and -) when (at least) one |
| 859 // of the operands is a literal smi. With this optimization, the | 859 // of the operands is a literal smi. With this optimization, the |
| 860 // performance of the system is increased by ~15%, and the generated | 860 // performance of the system is increased by ~15%, and the generated |
| 861 // code size is increased by ~1% (measured on a combination of | 861 // code size is increased by ~1% (measured on a combination of |
| 862 // different benchmarks). | 862 // different benchmarks). |
| 863 | 863 |
| 864 // sp[0] : operand | 864 // sp[0] : operand |
| 865 | 865 |
| 866 int int_value = Smi::cast(*value)->value(); | 866 int int_value = Smi::cast(*value)->value(); |
| 867 | 867 |
| 868 JumpTarget exit(this); | 868 JumpTarget exit; |
| 869 frame_->EmitPop(r0); | 869 frame_->EmitPop(r0); |
| 870 | 870 |
| 871 switch (op) { | 871 switch (op) { |
| 872 case Token::ADD: { | 872 case Token::ADD: { |
| 873 DeferredCode* deferred = | 873 DeferredCode* deferred = |
| 874 new DeferredInlineSmiOperation(this, op, int_value, reversed, mode); | 874 new DeferredInlineSmiOperation(this, op, int_value, reversed, mode); |
| 875 | 875 |
| 876 __ add(r0, r0, Operand(value), SetCC); | 876 __ add(r0, r0, Operand(value), SetCC); |
| 877 deferred->enter()->Branch(vs); | 877 deferred->enter()->Branch(vs); |
| 878 __ tst(r0, Operand(kSmiTagMask)); | 878 __ tst(r0, Operand(kSmiTagMask)); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 988 | 988 |
| 989 void CodeGenerator::Comparison(Condition cc, bool strict) { | 989 void CodeGenerator::Comparison(Condition cc, bool strict) { |
| 990 VirtualFrame::SpilledScope spilled_scope(this); | 990 VirtualFrame::SpilledScope spilled_scope(this); |
| 991 // sp[0] : y | 991 // sp[0] : y |
| 992 // sp[1] : x | 992 // sp[1] : x |
| 993 // result : cc register | 993 // result : cc register |
| 994 | 994 |
| 995 // Strict only makes sense for equality comparisons. | 995 // Strict only makes sense for equality comparisons. |
| 996 ASSERT(!strict || cc == eq); | 996 ASSERT(!strict || cc == eq); |
| 997 | 997 |
| 998 JumpTarget exit(this); | 998 JumpTarget exit; |
| 999 JumpTarget smi(this); | 999 JumpTarget smi; |
| 1000 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1000 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1001 if (cc == gt || cc == le) { | 1001 if (cc == gt || cc == le) { |
| 1002 cc = ReverseCondition(cc); | 1002 cc = ReverseCondition(cc); |
| 1003 frame_->EmitPop(r1); | 1003 frame_->EmitPop(r1); |
| 1004 frame_->EmitPop(r0); | 1004 frame_->EmitPop(r0); |
| 1005 } else { | 1005 } else { |
| 1006 frame_->EmitPop(r0); | 1006 frame_->EmitPop(r0); |
| 1007 frame_->EmitPop(r1); | 1007 frame_->EmitPop(r1); |
| 1008 } | 1008 } |
| 1009 __ orr(r2, r0, Operand(r1)); | 1009 __ orr(r2, r0, Operand(r1)); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1149 } | 1149 } |
| 1150 | 1150 |
| 1151 | 1151 |
| 1152 void CodeGenerator::VisitBlock(Block* node) { | 1152 void CodeGenerator::VisitBlock(Block* node) { |
| 1153 #ifdef DEBUG | 1153 #ifdef DEBUG |
| 1154 int original_height = frame_->height(); | 1154 int original_height = frame_->height(); |
| 1155 #endif | 1155 #endif |
| 1156 VirtualFrame::SpilledScope spilled_scope(this); | 1156 VirtualFrame::SpilledScope spilled_scope(this); |
| 1157 Comment cmnt(masm_, "[ Block"); | 1157 Comment cmnt(masm_, "[ Block"); |
| 1158 CodeForStatementPosition(node); | 1158 CodeForStatementPosition(node); |
| 1159 node->break_target()->Initialize(this); | 1159 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1160 VisitStatementsAndSpill(node->statements()); | 1160 VisitStatementsAndSpill(node->statements()); |
| 1161 if (node->break_target()->is_linked()) { | 1161 if (node->break_target()->is_linked()) { |
| 1162 node->break_target()->Bind(); | 1162 node->break_target()->Bind(); |
| 1163 } | 1163 } |
| 1164 node->break_target()->Unuse(); | 1164 node->break_target()->Unuse(); |
| 1165 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1165 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
| 1166 } | 1166 } |
| 1167 | 1167 |
| 1168 | 1168 |
| 1169 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1169 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1283 #endif | 1283 #endif |
| 1284 VirtualFrame::SpilledScope spilled_scope(this); | 1284 VirtualFrame::SpilledScope spilled_scope(this); |
| 1285 Comment cmnt(masm_, "[ IfStatement"); | 1285 Comment cmnt(masm_, "[ IfStatement"); |
| 1286 // Generate different code depending on which parts of the if statement | 1286 // Generate different code depending on which parts of the if statement |
| 1287 // are present or not. | 1287 // are present or not. |
| 1288 bool has_then_stm = node->HasThenStatement(); | 1288 bool has_then_stm = node->HasThenStatement(); |
| 1289 bool has_else_stm = node->HasElseStatement(); | 1289 bool has_else_stm = node->HasElseStatement(); |
| 1290 | 1290 |
| 1291 CodeForStatementPosition(node); | 1291 CodeForStatementPosition(node); |
| 1292 | 1292 |
| 1293 JumpTarget exit(this); | 1293 JumpTarget exit; |
| 1294 if (has_then_stm && has_else_stm) { | 1294 if (has_then_stm && has_else_stm) { |
| 1295 Comment cmnt(masm_, "[ IfThenElse"); | 1295 Comment cmnt(masm_, "[ IfThenElse"); |
| 1296 JumpTarget then(this); | 1296 JumpTarget then; |
| 1297 JumpTarget else_(this); | 1297 JumpTarget else_; |
| 1298 // if (cond) | 1298 // if (cond) |
| 1299 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, | 1299 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 1300 &then, &else_, true); | 1300 &then, &else_, true); |
| 1301 if (frame_ != NULL) { | 1301 if (frame_ != NULL) { |
| 1302 Branch(false, &else_); | 1302 Branch(false, &else_); |
| 1303 } | 1303 } |
| 1304 // then | 1304 // then |
| 1305 if (frame_ != NULL || then.is_linked()) { | 1305 if (frame_ != NULL || then.is_linked()) { |
| 1306 then.Bind(); | 1306 then.Bind(); |
| 1307 VisitAndSpill(node->then_statement()); | 1307 VisitAndSpill(node->then_statement()); |
| 1308 } | 1308 } |
| 1309 if (frame_ != NULL) { | 1309 if (frame_ != NULL) { |
| 1310 exit.Jump(); | 1310 exit.Jump(); |
| 1311 } | 1311 } |
| 1312 // else | 1312 // else |
| 1313 if (else_.is_linked()) { | 1313 if (else_.is_linked()) { |
| 1314 else_.Bind(); | 1314 else_.Bind(); |
| 1315 VisitAndSpill(node->else_statement()); | 1315 VisitAndSpill(node->else_statement()); |
| 1316 } | 1316 } |
| 1317 | 1317 |
| 1318 } else if (has_then_stm) { | 1318 } else if (has_then_stm) { |
| 1319 Comment cmnt(masm_, "[ IfThen"); | 1319 Comment cmnt(masm_, "[ IfThen"); |
| 1320 ASSERT(!has_else_stm); | 1320 ASSERT(!has_else_stm); |
| 1321 JumpTarget then(this); | 1321 JumpTarget then; |
| 1322 // if (cond) | 1322 // if (cond) |
| 1323 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, | 1323 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 1324 &then, &exit, true); | 1324 &then, &exit, true); |
| 1325 if (frame_ != NULL) { | 1325 if (frame_ != NULL) { |
| 1326 Branch(false, &exit); | 1326 Branch(false, &exit); |
| 1327 } | 1327 } |
| 1328 // then | 1328 // then |
| 1329 if (frame_ != NULL || then.is_linked()) { | 1329 if (frame_ != NULL || then.is_linked()) { |
| 1330 then.Bind(); | 1330 then.Bind(); |
| 1331 VisitAndSpill(node->then_statement()); | 1331 VisitAndSpill(node->then_statement()); |
| 1332 } | 1332 } |
| 1333 | 1333 |
| 1334 } else if (has_else_stm) { | 1334 } else if (has_else_stm) { |
| 1335 Comment cmnt(masm_, "[ IfElse"); | 1335 Comment cmnt(masm_, "[ IfElse"); |
| 1336 ASSERT(!has_then_stm); | 1336 ASSERT(!has_then_stm); |
| 1337 JumpTarget else_(this); | 1337 JumpTarget else_; |
| 1338 // if (!cond) | 1338 // if (!cond) |
| 1339 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, | 1339 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 1340 &exit, &else_, true); | 1340 &exit, &else_, true); |
| 1341 if (frame_ != NULL) { | 1341 if (frame_ != NULL) { |
| 1342 Branch(true, &exit); | 1342 Branch(true, &exit); |
| 1343 } | 1343 } |
| 1344 // else | 1344 // else |
| 1345 if (frame_ != NULL || else_.is_linked()) { | 1345 if (frame_ != NULL || else_.is_linked()) { |
| 1346 else_.Bind(); | 1346 else_.Bind(); |
| 1347 VisitAndSpill(node->else_statement()); | 1347 VisitAndSpill(node->else_statement()); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1417 VirtualFrame::SpilledScope spilled_scope(this); | 1417 VirtualFrame::SpilledScope spilled_scope(this); |
| 1418 Comment cmnt(masm_, "[ WithEnterStatement"); | 1418 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1419 CodeForStatementPosition(node); | 1419 CodeForStatementPosition(node); |
| 1420 LoadAndSpill(node->expression()); | 1420 LoadAndSpill(node->expression()); |
| 1421 if (node->is_catch_block()) { | 1421 if (node->is_catch_block()) { |
| 1422 frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 1422 frame_->CallRuntime(Runtime::kPushCatchContext, 1); |
| 1423 } else { | 1423 } else { |
| 1424 frame_->CallRuntime(Runtime::kPushContext, 1); | 1424 frame_->CallRuntime(Runtime::kPushContext, 1); |
| 1425 } | 1425 } |
| 1426 #ifdef DEBUG | 1426 #ifdef DEBUG |
| 1427 JumpTarget verified_true(this); | 1427 JumpTarget verified_true; |
| 1428 __ cmp(r0, Operand(cp)); | 1428 __ cmp(r0, Operand(cp)); |
| 1429 verified_true.Branch(eq); | 1429 verified_true.Branch(eq); |
| 1430 __ stop("PushContext: r0 is expected to be the same as cp"); | 1430 __ stop("PushContext: r0 is expected to be the same as cp"); |
| 1431 verified_true.Bind(); | 1431 verified_true.Bind(); |
| 1432 #endif | 1432 #endif |
| 1433 // Update context local. | 1433 // Update context local. |
| 1434 __ str(cp, frame_->Context()); | 1434 __ str(cp, frame_->Context()); |
| 1435 ASSERT(frame_->height() == original_height); | 1435 ASSERT(frame_->height() == original_height); |
| 1436 } | 1436 } |
| 1437 | 1437 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1461 | 1461 |
| 1462 | 1462 |
| 1463 void CodeGenerator::GenerateFastCaseSwitchJumpTable( | 1463 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
| 1464 SwitchStatement* node, | 1464 SwitchStatement* node, |
| 1465 int min_index, | 1465 int min_index, |
| 1466 int range, | 1466 int range, |
| 1467 Label* default_label, | 1467 Label* default_label, |
| 1468 Vector<Label*> case_targets, | 1468 Vector<Label*> case_targets, |
| 1469 Vector<Label> case_labels) { | 1469 Vector<Label> case_labels) { |
| 1470 VirtualFrame::SpilledScope spilled_scope(this); | 1470 VirtualFrame::SpilledScope spilled_scope(this); |
| 1471 JumpTarget setup_default(this); | 1471 JumpTarget setup_default; |
| 1472 JumpTarget is_smi(this); | 1472 JumpTarget is_smi; |
| 1473 | 1473 |
| 1474 // A non-null default label pointer indicates a default case among | 1474 // A non-null default label pointer indicates a default case among |
| 1475 // the case labels. Otherwise we use the break target as a | 1475 // the case labels. Otherwise we use the break target as a |
| 1476 // "default" for failure to hit the jump table. | 1476 // "default" for failure to hit the jump table. |
| 1477 JumpTarget* default_target = | 1477 JumpTarget* default_target = |
| 1478 (default_label == NULL) ? node->break_target() : &setup_default; | 1478 (default_label == NULL) ? node->break_target() : &setup_default; |
| 1479 | 1479 |
| 1480 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); | 1480 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); |
| 1481 frame_->EmitPop(r0); | 1481 frame_->EmitPop(r0); |
| 1482 | 1482 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1532 } | 1532 } |
| 1533 | 1533 |
| 1534 | 1534 |
| 1535 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1535 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1536 #ifdef DEBUG | 1536 #ifdef DEBUG |
| 1537 int original_height = frame_->height(); | 1537 int original_height = frame_->height(); |
| 1538 #endif | 1538 #endif |
| 1539 VirtualFrame::SpilledScope spilled_scope(this); | 1539 VirtualFrame::SpilledScope spilled_scope(this); |
| 1540 Comment cmnt(masm_, "[ SwitchStatement"); | 1540 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1541 CodeForStatementPosition(node); | 1541 CodeForStatementPosition(node); |
| 1542 node->break_target()->Initialize(this); | 1542 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1543 | 1543 |
| 1544 LoadAndSpill(node->tag()); | 1544 LoadAndSpill(node->tag()); |
| 1545 if (TryGenerateFastCaseSwitchStatement(node)) { | 1545 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1546 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1546 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
| 1547 return; | 1547 return; |
| 1548 } | 1548 } |
| 1549 | 1549 |
| 1550 JumpTarget next_test(this); | 1550 JumpTarget next_test; |
| 1551 JumpTarget fall_through(this); | 1551 JumpTarget fall_through; |
| 1552 JumpTarget default_entry(this); | 1552 JumpTarget default_entry; |
| 1553 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL); | 1553 JumpTarget default_exit(JumpTarget::BIDIRECTIONAL); |
| 1554 ZoneList<CaseClause*>* cases = node->cases(); | 1554 ZoneList<CaseClause*>* cases = node->cases(); |
| 1555 int length = cases->length(); | 1555 int length = cases->length(); |
| 1556 CaseClause* default_clause = NULL; | 1556 CaseClause* default_clause = NULL; |
| 1557 | 1557 |
| 1558 for (int i = 0; i < length; i++) { | 1558 for (int i = 0; i < length; i++) { |
| 1559 CaseClause* clause = cases->at(i); | 1559 CaseClause* clause = cases->at(i); |
| 1560 if (clause->is_default()) { | 1560 if (clause->is_default()) { |
| 1561 // Remember the default clause and compile it at the end. | 1561 // Remember the default clause and compile it at the end. |
| 1562 default_clause = clause; | 1562 default_clause = clause; |
| 1563 continue; | 1563 continue; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1626 } | 1626 } |
| 1627 | 1627 |
| 1628 | 1628 |
| 1629 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1629 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1630 #ifdef DEBUG | 1630 #ifdef DEBUG |
| 1631 int original_height = frame_->height(); | 1631 int original_height = frame_->height(); |
| 1632 #endif | 1632 #endif |
| 1633 VirtualFrame::SpilledScope spilled_scope(this); | 1633 VirtualFrame::SpilledScope spilled_scope(this); |
| 1634 Comment cmnt(masm_, "[ LoopStatement"); | 1634 Comment cmnt(masm_, "[ LoopStatement"); |
| 1635 CodeForStatementPosition(node); | 1635 CodeForStatementPosition(node); |
| 1636 node->break_target()->Initialize(this); | 1636 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1637 | 1637 |
| 1638 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 1638 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 1639 // known result for the test expression, with no side effects. | 1639 // known result for the test expression, with no side effects. |
| 1640 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1640 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1641 if (node->cond() == NULL) { | 1641 if (node->cond() == NULL) { |
| 1642 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1642 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1643 info = ALWAYS_TRUE; | 1643 info = ALWAYS_TRUE; |
| 1644 } else { | 1644 } else { |
| 1645 Literal* lit = node->cond()->AsLiteral(); | 1645 Literal* lit = node->cond()->AsLiteral(); |
| 1646 if (lit != NULL) { | 1646 if (lit != NULL) { |
| 1647 if (lit->IsTrue()) { | 1647 if (lit->IsTrue()) { |
| 1648 info = ALWAYS_TRUE; | 1648 info = ALWAYS_TRUE; |
| 1649 } else if (lit->IsFalse()) { | 1649 } else if (lit->IsFalse()) { |
| 1650 info = ALWAYS_FALSE; | 1650 info = ALWAYS_FALSE; |
| 1651 } | 1651 } |
| 1652 } | 1652 } |
| 1653 } | 1653 } |
| 1654 | 1654 |
| 1655 switch (node->type()) { | 1655 switch (node->type()) { |
| 1656 case LoopStatement::DO_LOOP: { | 1656 case LoopStatement::DO_LOOP: { |
| 1657 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); | 1657 JumpTarget body(JumpTarget::BIDIRECTIONAL); |
| 1658 | 1658 |
| 1659 // Label the top of the loop for the backward CFG edge. If the test | 1659 // Label the top of the loop for the backward CFG edge. If the test |
| 1660 // is always true we can use the continue target, and if the test is | 1660 // is always true we can use the continue target, and if the test is |
| 1661 // always false there is no need. | 1661 // always false there is no need. |
| 1662 if (info == ALWAYS_TRUE) { | 1662 if (info == ALWAYS_TRUE) { |
| 1663 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 1663 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
| 1664 node->continue_target()->Bind(); | 1664 node->continue_target()->Bind(); |
| 1665 } else if (info == ALWAYS_FALSE) { | 1665 } else if (info == ALWAYS_FALSE) { |
| 1666 node->continue_target()->Initialize(this); | 1666 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1667 } else { | 1667 } else { |
| 1668 ASSERT(info == DONT_KNOW); | 1668 ASSERT(info == DONT_KNOW); |
| 1669 node->continue_target()->Initialize(this); | 1669 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1670 body.Bind(); | 1670 body.Bind(); |
| 1671 } | 1671 } |
| 1672 | 1672 |
| 1673 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1673 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1674 VisitAndSpill(node->body()); | 1674 VisitAndSpill(node->body()); |
| 1675 | 1675 |
| 1676 // Compile the test. | 1676 // Compile the test. |
| 1677 if (info == ALWAYS_TRUE) { | 1677 if (info == ALWAYS_TRUE) { |
| 1678 if (has_valid_frame()) { | 1678 if (has_valid_frame()) { |
| 1679 // If control can fall off the end of the body, jump back to the | 1679 // If control can fall off the end of the body, jump back to the |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1706 break; | 1706 break; |
| 1707 } | 1707 } |
| 1708 | 1708 |
| 1709 case LoopStatement::WHILE_LOOP: { | 1709 case LoopStatement::WHILE_LOOP: { |
| 1710 // If the test is never true and has no side effects there is no need | 1710 // If the test is never true and has no side effects there is no need |
| 1711 // to compile the test or body. | 1711 // to compile the test or body. |
| 1712 if (info == ALWAYS_FALSE) break; | 1712 if (info == ALWAYS_FALSE) break; |
| 1713 | 1713 |
| 1714 // Label the top of the loop with the continue target for the backward | 1714 // Label the top of the loop with the continue target for the backward |
| 1715 // CFG edge. | 1715 // CFG edge. |
| 1716 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 1716 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
| 1717 node->continue_target()->Bind(); | 1717 node->continue_target()->Bind(); |
| 1718 | 1718 |
| 1719 if (info == DONT_KNOW) { | 1719 if (info == DONT_KNOW) { |
| 1720 JumpTarget body(this); | 1720 JumpTarget body; |
| 1721 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, | 1721 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, |
| 1722 &body, node->break_target(), true); | 1722 &body, node->break_target(), true); |
| 1723 if (has_valid_frame()) { | 1723 if (has_valid_frame()) { |
| 1724 // A NULL frame indicates that control did not fall out of the | 1724 // A NULL frame indicates that control did not fall out of the |
| 1725 // test expression. | 1725 // test expression. |
| 1726 Branch(false, node->break_target()); | 1726 Branch(false, node->break_target()); |
| 1727 } | 1727 } |
| 1728 if (has_valid_frame() || body.is_linked()) { | 1728 if (has_valid_frame() || body.is_linked()) { |
| 1729 body.Bind(); | 1729 body.Bind(); |
| 1730 } | 1730 } |
| 1731 } | 1731 } |
| 1732 | 1732 |
| 1733 if (has_valid_frame()) { | 1733 if (has_valid_frame()) { |
| 1734 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1734 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1735 VisitAndSpill(node->body()); | 1735 VisitAndSpill(node->body()); |
| 1736 | 1736 |
| 1737 // If control flow can fall out of the body, jump back to the top. | 1737 // If control flow can fall out of the body, jump back to the top. |
| 1738 if (has_valid_frame()) { | 1738 if (has_valid_frame()) { |
| 1739 node->continue_target()->Jump(); | 1739 node->continue_target()->Jump(); |
| 1740 } | 1740 } |
| 1741 } | 1741 } |
| 1742 break; | 1742 break; |
| 1743 } | 1743 } |
| 1744 | 1744 |
| 1745 case LoopStatement::FOR_LOOP: { | 1745 case LoopStatement::FOR_LOOP: { |
| 1746 JumpTarget loop(this, JumpTarget::BIDIRECTIONAL); | 1746 JumpTarget loop(JumpTarget::BIDIRECTIONAL); |
| 1747 | 1747 |
| 1748 if (node->init() != NULL) { | 1748 if (node->init() != NULL) { |
| 1749 VisitAndSpill(node->init()); | 1749 VisitAndSpill(node->init()); |
| 1750 } | 1750 } |
| 1751 | 1751 |
| 1752 // There is no need to compile the test or body. | 1752 // There is no need to compile the test or body. |
| 1753 if (info == ALWAYS_FALSE) break; | 1753 if (info == ALWAYS_FALSE) break; |
| 1754 | 1754 |
| 1755 // If there is no update statement, label the top of the loop with the | 1755 // If there is no update statement, label the top of the loop with the |
| 1756 // continue target, otherwise with the loop target. | 1756 // continue target, otherwise with the loop target. |
| 1757 if (node->next() == NULL) { | 1757 if (node->next() == NULL) { |
| 1758 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 1758 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
| 1759 node->continue_target()->Bind(); | 1759 node->continue_target()->Bind(); |
| 1760 } else { | 1760 } else { |
| 1761 node->continue_target()->Initialize(this); | 1761 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1762 loop.Bind(); | 1762 loop.Bind(); |
| 1763 } | 1763 } |
| 1764 | 1764 |
| 1765 // If the test is always true, there is no need to compile it. | 1765 // If the test is always true, there is no need to compile it. |
| 1766 if (info == DONT_KNOW) { | 1766 if (info == DONT_KNOW) { |
| 1767 JumpTarget body(this); | 1767 JumpTarget body; |
| 1768 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, | 1768 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, |
| 1769 &body, node->break_target(), true); | 1769 &body, node->break_target(), true); |
| 1770 if (has_valid_frame()) { | 1770 if (has_valid_frame()) { |
| 1771 Branch(false, node->break_target()); | 1771 Branch(false, node->break_target()); |
| 1772 } | 1772 } |
| 1773 if (has_valid_frame() || body.is_linked()) { | 1773 if (has_valid_frame() || body.is_linked()) { |
| 1774 body.Bind(); | 1774 body.Bind(); |
| 1775 } | 1775 } |
| 1776 } | 1776 } |
| 1777 | 1777 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1817 | 1817 |
| 1818 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1818 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1819 #ifdef DEBUG | 1819 #ifdef DEBUG |
| 1820 int original_height = frame_->height(); | 1820 int original_height = frame_->height(); |
| 1821 #endif | 1821 #endif |
| 1822 ASSERT(!in_spilled_code()); | 1822 ASSERT(!in_spilled_code()); |
| 1823 VirtualFrame::SpilledScope spilled_scope(this); | 1823 VirtualFrame::SpilledScope spilled_scope(this); |
| 1824 Comment cmnt(masm_, "[ ForInStatement"); | 1824 Comment cmnt(masm_, "[ ForInStatement"); |
| 1825 CodeForStatementPosition(node); | 1825 CodeForStatementPosition(node); |
| 1826 | 1826 |
| 1827 JumpTarget primitive(this); | 1827 JumpTarget primitive; |
| 1828 JumpTarget jsobject(this); | 1828 JumpTarget jsobject; |
| 1829 JumpTarget fixed_array(this); | 1829 JumpTarget fixed_array; |
| 1830 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL); | 1830 JumpTarget entry(JumpTarget::BIDIRECTIONAL); |
| 1831 JumpTarget end_del_check(this); | 1831 JumpTarget end_del_check; |
| 1832 JumpTarget exit(this); | 1832 JumpTarget exit; |
| 1833 | 1833 |
| 1834 // Get the object to enumerate over (converted to JSObject). | 1834 // Get the object to enumerate over (converted to JSObject). |
| 1835 LoadAndSpill(node->enumerable()); | 1835 LoadAndSpill(node->enumerable()); |
| 1836 | 1836 |
| 1837 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1837 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 1838 // to the specification. 12.6.4 mandates a call to ToObject. | 1838 // to the specification. 12.6.4 mandates a call to ToObject. |
| 1839 frame_->EmitPop(r0); | 1839 frame_->EmitPop(r0); |
| 1840 __ cmp(r0, Operand(Factory::undefined_value())); | 1840 __ cmp(r0, Operand(Factory::undefined_value())); |
| 1841 exit.Branch(eq); | 1841 exit.Branch(eq); |
| 1842 __ cmp(r0, Operand(Factory::null_value())); | 1842 __ cmp(r0, Operand(Factory::null_value())); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1907 | 1907 |
| 1908 // Condition. | 1908 // Condition. |
| 1909 entry.Bind(); | 1909 entry.Bind(); |
| 1910 // sp[0] : index | 1910 // sp[0] : index |
| 1911 // sp[1] : array/enum cache length | 1911 // sp[1] : array/enum cache length |
| 1912 // sp[2] : array or enum cache | 1912 // sp[2] : array or enum cache |
| 1913 // sp[3] : 0 or map | 1913 // sp[3] : 0 or map |
| 1914 // sp[4] : enumerable | 1914 // sp[4] : enumerable |
| 1915 // Grab the current frame's height for the break and continue | 1915 // Grab the current frame's height for the break and continue |
| 1916 // targets only after all the state is pushed on the frame. | 1916 // targets only after all the state is pushed on the frame. |
| 1917 node->break_target()->Initialize(this); | 1917 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1918 node->continue_target()->Initialize(this); | 1918 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 1919 | 1919 |
| 1920 __ ldr(r0, frame_->ElementAt(0)); // load the current count | 1920 __ ldr(r0, frame_->ElementAt(0)); // load the current count |
| 1921 __ ldr(r1, frame_->ElementAt(1)); // load the length | 1921 __ ldr(r1, frame_->ElementAt(1)); // load the length |
| 1922 __ cmp(r0, Operand(r1)); // compare to the array length | 1922 __ cmp(r0, Operand(r1)); // compare to the array length |
| 1923 node->break_target()->Branch(hs); | 1923 node->break_target()->Branch(hs); |
| 1924 | 1924 |
| 1925 __ ldr(r0, frame_->ElementAt(0)); | 1925 __ ldr(r0, frame_->ElementAt(0)); |
| 1926 | 1926 |
| 1927 // Get the i'th entry of the array. | 1927 // Get the i'th entry of the array. |
| 1928 __ ldr(r2, frame_->ElementAt(2)); | 1928 __ ldr(r2, frame_->ElementAt(2)); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2011 | 2011 |
| 2012 | 2012 |
| 2013 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2013 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 2014 #ifdef DEBUG | 2014 #ifdef DEBUG |
| 2015 int original_height = frame_->height(); | 2015 int original_height = frame_->height(); |
| 2016 #endif | 2016 #endif |
| 2017 VirtualFrame::SpilledScope spilled_scope(this); | 2017 VirtualFrame::SpilledScope spilled_scope(this); |
| 2018 Comment cmnt(masm_, "[ TryCatch"); | 2018 Comment cmnt(masm_, "[ TryCatch"); |
| 2019 CodeForStatementPosition(node); | 2019 CodeForStatementPosition(node); |
| 2020 | 2020 |
| 2021 JumpTarget try_block(this); | 2021 JumpTarget try_block; |
| 2022 JumpTarget exit(this); | 2022 JumpTarget exit; |
| 2023 | 2023 |
| 2024 try_block.Call(); | 2024 try_block.Call(); |
| 2025 // --- Catch block --- | 2025 // --- Catch block --- |
| 2026 frame_->EmitPush(r0); | 2026 frame_->EmitPush(r0); |
| 2027 | 2027 |
| 2028 // Store the caught exception in the catch variable. | 2028 // Store the caught exception in the catch variable. |
| 2029 { Reference ref(this, node->catch_var()); | 2029 { Reference ref(this, node->catch_var()); |
| 2030 ASSERT(ref.is_slot()); | 2030 ASSERT(ref.is_slot()); |
| 2031 // Here we make use of the convenient property that it doesn't matter | 2031 // Here we make use of the convenient property that it doesn't matter |
| 2032 // whether a value is immediately on top of or underneath a zero-sized | 2032 // whether a value is immediately on top of or underneath a zero-sized |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2143 #endif | 2143 #endif |
| 2144 VirtualFrame::SpilledScope spilled_scope(this); | 2144 VirtualFrame::SpilledScope spilled_scope(this); |
| 2145 Comment cmnt(masm_, "[ TryFinally"); | 2145 Comment cmnt(masm_, "[ TryFinally"); |
| 2146 CodeForStatementPosition(node); | 2146 CodeForStatementPosition(node); |
| 2147 | 2147 |
| 2148 // State: Used to keep track of reason for entering the finally | 2148 // State: Used to keep track of reason for entering the finally |
| 2149 // block. Should probably be extended to hold information for | 2149 // block. Should probably be extended to hold information for |
| 2150 // break/continue from within the try block. | 2150 // break/continue from within the try block. |
| 2151 enum { FALLING, THROWING, JUMPING }; | 2151 enum { FALLING, THROWING, JUMPING }; |
| 2152 | 2152 |
| 2153 JumpTarget try_block(this); | 2153 JumpTarget try_block; |
| 2154 JumpTarget finally_block(this); | 2154 JumpTarget finally_block; |
| 2155 | 2155 |
| 2156 try_block.Call(); | 2156 try_block.Call(); |
| 2157 | 2157 |
| 2158 frame_->EmitPush(r0); // save exception object on the stack | 2158 frame_->EmitPush(r0); // save exception object on the stack |
| 2159 // In case of thrown exceptions, this is where we continue. | 2159 // In case of thrown exceptions, this is where we continue. |
| 2160 __ mov(r2, Operand(Smi::FromInt(THROWING))); | 2160 __ mov(r2, Operand(Smi::FromInt(THROWING))); |
| 2161 finally_block.Jump(); | 2161 finally_block.Jump(); |
| 2162 | 2162 |
| 2163 // --- Try block --- | 2163 // --- Try block --- |
| 2164 try_block.Bind(); | 2164 try_block.Bind(); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2289 frame_->EmitPop(r0); | 2289 frame_->EmitPop(r0); |
| 2290 } | 2290 } |
| 2291 | 2291 |
| 2292 // Generate code to jump to the right destination for all used | 2292 // Generate code to jump to the right destination for all used |
| 2293 // formerly shadowing targets. Deallocate each shadow target. | 2293 // formerly shadowing targets. Deallocate each shadow target. |
| 2294 for (int i = 0; i < shadows.length(); i++) { | 2294 for (int i = 0; i < shadows.length(); i++) { |
| 2295 if (has_valid_frame() && shadows[i]->is_bound()) { | 2295 if (has_valid_frame() && shadows[i]->is_bound()) { |
| 2296 JumpTarget* original = shadows[i]->other_target(); | 2296 JumpTarget* original = shadows[i]->other_target(); |
| 2297 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); | 2297 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); |
| 2298 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { | 2298 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { |
| 2299 JumpTarget skip(this); | 2299 JumpTarget skip; |
| 2300 skip.Branch(ne); | 2300 skip.Branch(ne); |
| 2301 frame_->PrepareForReturn(); | 2301 frame_->PrepareForReturn(); |
| 2302 original->Jump(); | 2302 original->Jump(); |
| 2303 skip.Bind(); | 2303 skip.Bind(); |
| 2304 } else { | 2304 } else { |
| 2305 original->Branch(eq); | 2305 original->Branch(eq); |
| 2306 } | 2306 } |
| 2307 } | 2307 } |
| 2308 } | 2308 } |
| 2309 | 2309 |
| 2310 if (has_valid_frame()) { | 2310 if (has_valid_frame()) { |
| 2311 // Check if we need to rethrow the exception. | 2311 // Check if we need to rethrow the exception. |
| 2312 JumpTarget exit(this); | 2312 JumpTarget exit; |
| 2313 __ cmp(r2, Operand(Smi::FromInt(THROWING))); | 2313 __ cmp(r2, Operand(Smi::FromInt(THROWING))); |
| 2314 exit.Branch(ne); | 2314 exit.Branch(ne); |
| 2315 | 2315 |
| 2316 // Rethrow exception. | 2316 // Rethrow exception. |
| 2317 frame_->EmitPush(r0); | 2317 frame_->EmitPush(r0); |
| 2318 frame_->CallRuntime(Runtime::kReThrow, 1); | 2318 frame_->CallRuntime(Runtime::kReThrow, 1); |
| 2319 | 2319 |
| 2320 // Done. | 2320 // Done. |
| 2321 exit.Bind(); | 2321 exit.Bind(); |
| 2322 } | 2322 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2384 ASSERT(frame_->height() == original_height + 1); | 2384 ASSERT(frame_->height() == original_height + 1); |
| 2385 } | 2385 } |
| 2386 | 2386 |
| 2387 | 2387 |
| 2388 void CodeGenerator::VisitConditional(Conditional* node) { | 2388 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2389 #ifdef DEBUG | 2389 #ifdef DEBUG |
| 2390 int original_height = frame_->height(); | 2390 int original_height = frame_->height(); |
| 2391 #endif | 2391 #endif |
| 2392 VirtualFrame::SpilledScope spilled_scope(this); | 2392 VirtualFrame::SpilledScope spilled_scope(this); |
| 2393 Comment cmnt(masm_, "[ Conditional"); | 2393 Comment cmnt(masm_, "[ Conditional"); |
| 2394 JumpTarget then(this); | 2394 JumpTarget then; |
| 2395 JumpTarget else_(this); | 2395 JumpTarget else_; |
| 2396 JumpTarget exit(this); | 2396 JumpTarget exit; |
| 2397 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, | 2397 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 2398 &then, &else_, true); | 2398 &then, &else_, true); |
| 2399 Branch(false, &else_); | 2399 Branch(false, &else_); |
| 2400 then.Bind(); | 2400 then.Bind(); |
| 2401 LoadAndSpill(node->then_expression(), typeof_state()); | 2401 LoadAndSpill(node->then_expression(), typeof_state()); |
| 2402 exit.Jump(); | 2402 exit.Jump(); |
| 2403 else_.Bind(); | 2403 else_.Bind(); |
| 2404 LoadAndSpill(node->else_expression(), typeof_state()); | 2404 LoadAndSpill(node->else_expression(), typeof_state()); |
| 2405 exit.Bind(); | 2405 exit.Bind(); |
| 2406 ASSERT(frame_->height() == original_height + 1); | 2406 ASSERT(frame_->height() == original_height + 1); |
| 2407 } | 2407 } |
| 2408 | 2408 |
| 2409 | 2409 |
| 2410 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2410 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2411 VirtualFrame::SpilledScope spilled_scope(this); | 2411 VirtualFrame::SpilledScope spilled_scope(this); |
| 2412 if (slot->type() == Slot::LOOKUP) { | 2412 if (slot->type() == Slot::LOOKUP) { |
| 2413 ASSERT(slot->var()->is_dynamic()); | 2413 ASSERT(slot->var()->is_dynamic()); |
| 2414 | 2414 |
| 2415 JumpTarget slow(this); | 2415 JumpTarget slow; |
| 2416 JumpTarget done(this); | 2416 JumpTarget done; |
| 2417 | 2417 |
| 2418 // Generate fast-case code for variables that might be shadowed by | 2418 // Generate fast-case code for variables that might be shadowed by |
| 2419 // eval-introduced variables. Eval is used a lot without | 2419 // eval-introduced variables. Eval is used a lot without |
| 2420 // introducing variables. In those cases, we do not want to | 2420 // introducing variables. In those cases, we do not want to |
| 2421 // perform a runtime call for all variables in the scope | 2421 // perform a runtime call for all variables in the scope |
| 2422 // containing the eval. | 2422 // containing the eval. |
| 2423 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 2423 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 2424 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow); | 2424 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow); |
| 2425 // If there was no control flow to slow, we can exit early. | 2425 // If there was no control flow to slow, we can exit early. |
| 2426 if (!slow.is_linked()) { | 2426 if (!slow.is_linked()) { |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2613 __ ldr(r1, frame_->Function()); | 2613 __ ldr(r1, frame_->Function()); |
| 2614 | 2614 |
| 2615 // Load the literals array of the function. | 2615 // Load the literals array of the function. |
| 2616 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 2616 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
| 2617 | 2617 |
| 2618 // Load the literal at the ast saved index. | 2618 // Load the literal at the ast saved index. |
| 2619 int literal_offset = | 2619 int literal_offset = |
| 2620 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2620 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
| 2621 __ ldr(r2, FieldMemOperand(r1, literal_offset)); | 2621 __ ldr(r2, FieldMemOperand(r1, literal_offset)); |
| 2622 | 2622 |
| 2623 JumpTarget done(this); | 2623 JumpTarget done; |
| 2624 __ cmp(r2, Operand(Factory::undefined_value())); | 2624 __ cmp(r2, Operand(Factory::undefined_value())); |
| 2625 done.Branch(ne); | 2625 done.Branch(ne); |
| 2626 | 2626 |
| 2627 // If the entry is undefined we call the runtime system to computed | 2627 // If the entry is undefined we call the runtime system to computed |
| 2628 // the literal. | 2628 // the literal. |
| 2629 frame_->EmitPush(r1); // literal array (0) | 2629 frame_->EmitPush(r1); // literal array (0) |
| 2630 __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); | 2630 __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); |
| 2631 frame_->EmitPush(r0); // literal index (1) | 2631 frame_->EmitPush(r0); // literal index (1) |
| 2632 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) | 2632 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) |
| 2633 frame_->EmitPush(r0); | 2633 frame_->EmitPush(r0); |
| (...skipping 625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3259 | 3259 |
| 3260 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). | 3260 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). |
| 3261 __ str(r0, frame_->Top()); | 3261 __ str(r0, frame_->Top()); |
| 3262 ASSERT(frame_->height() == original_height + 1); | 3262 ASSERT(frame_->height() == original_height + 1); |
| 3263 } | 3263 } |
| 3264 | 3264 |
| 3265 | 3265 |
| 3266 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3266 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 3267 VirtualFrame::SpilledScope spilled_scope(this); | 3267 VirtualFrame::SpilledScope spilled_scope(this); |
| 3268 ASSERT(args->length() == 1); | 3268 ASSERT(args->length() == 1); |
| 3269 JumpTarget leave(this); | 3269 JumpTarget leave; |
| 3270 LoadAndSpill(args->at(0)); | 3270 LoadAndSpill(args->at(0)); |
| 3271 frame_->EmitPop(r0); // r0 contains object. | 3271 frame_->EmitPop(r0); // r0 contains object. |
| 3272 // if (object->IsSmi()) return the object. | 3272 // if (object->IsSmi()) return the object. |
| 3273 __ tst(r0, Operand(kSmiTagMask)); | 3273 __ tst(r0, Operand(kSmiTagMask)); |
| 3274 leave.Branch(eq); | 3274 leave.Branch(eq); |
| 3275 // It is a heap object - get map. | 3275 // It is a heap object - get map. |
| 3276 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3276 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 3277 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3277 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 3278 // if (!object->IsJSValue()) return the object. | 3278 // if (!object->IsJSValue()) return the object. |
| 3279 __ cmp(r1, Operand(JS_VALUE_TYPE)); | 3279 __ cmp(r1, Operand(JS_VALUE_TYPE)); |
| 3280 leave.Branch(ne); | 3280 leave.Branch(ne); |
| 3281 // Load the value. | 3281 // Load the value. |
| 3282 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); | 3282 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); |
| 3283 leave.Bind(); | 3283 leave.Bind(); |
| 3284 frame_->EmitPush(r0); | 3284 frame_->EmitPush(r0); |
| 3285 } | 3285 } |
| 3286 | 3286 |
| 3287 | 3287 |
| 3288 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 3288 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 3289 VirtualFrame::SpilledScope spilled_scope(this); | 3289 VirtualFrame::SpilledScope spilled_scope(this); |
| 3290 ASSERT(args->length() == 2); | 3290 ASSERT(args->length() == 2); |
| 3291 JumpTarget leave(this); | 3291 JumpTarget leave; |
| 3292 LoadAndSpill(args->at(0)); // Load the object. | 3292 LoadAndSpill(args->at(0)); // Load the object. |
| 3293 LoadAndSpill(args->at(1)); // Load the value. | 3293 LoadAndSpill(args->at(1)); // Load the value. |
| 3294 frame_->EmitPop(r0); // r0 contains value | 3294 frame_->EmitPop(r0); // r0 contains value |
| 3295 frame_->EmitPop(r1); // r1 contains object | 3295 frame_->EmitPop(r1); // r1 contains object |
| 3296 // if (object->IsSmi()) return object. | 3296 // if (object->IsSmi()) return object. |
| 3297 __ tst(r1, Operand(kSmiTagMask)); | 3297 __ tst(r1, Operand(kSmiTagMask)); |
| 3298 leave.Branch(eq); | 3298 leave.Branch(eq); |
| 3299 // It is a heap object - get map. | 3299 // It is a heap object - get map. |
| 3300 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3300 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3301 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 3301 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3357 ASSERT(args->length() == 2); | 3357 ASSERT(args->length() == 2); |
| 3358 __ mov(r0, Operand(Factory::undefined_value())); | 3358 __ mov(r0, Operand(Factory::undefined_value())); |
| 3359 frame_->EmitPush(r0); | 3359 frame_->EmitPush(r0); |
| 3360 } | 3360 } |
| 3361 | 3361 |
| 3362 | 3362 |
| 3363 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3363 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3364 VirtualFrame::SpilledScope spilled_scope(this); | 3364 VirtualFrame::SpilledScope spilled_scope(this); |
| 3365 ASSERT(args->length() == 1); | 3365 ASSERT(args->length() == 1); |
| 3366 LoadAndSpill(args->at(0)); | 3366 LoadAndSpill(args->at(0)); |
| 3367 JumpTarget answer(this); | 3367 JumpTarget answer; |
| 3368 // We need the CC bits to come out as not_equal in the case where the | 3368 // We need the CC bits to come out as not_equal in the case where the |
| 3369 // object is a smi. This can't be done with the usual test opcode so | 3369 // object is a smi. This can't be done with the usual test opcode so |
| 3370 // we use XOR to get the right CC bits. | 3370 // we use XOR to get the right CC bits. |
| 3371 frame_->EmitPop(r0); | 3371 frame_->EmitPop(r0); |
| 3372 __ and_(r1, r0, Operand(kSmiTagMask)); | 3372 __ and_(r1, r0, Operand(kSmiTagMask)); |
| 3373 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); | 3373 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
| 3374 answer.Branch(ne); | 3374 answer.Branch(ne); |
| 3375 // It is a heap object - get the map. | 3375 // It is a heap object - get the map. |
| 3376 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3376 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 3377 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3377 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3561 break; | 3561 break; |
| 3562 | 3562 |
| 3563 case Token::SUB: { | 3563 case Token::SUB: { |
| 3564 UnarySubStub stub; | 3564 UnarySubStub stub; |
| 3565 frame_->CallStub(&stub, 0); | 3565 frame_->CallStub(&stub, 0); |
| 3566 break; | 3566 break; |
| 3567 } | 3567 } |
| 3568 | 3568 |
| 3569 case Token::BIT_NOT: { | 3569 case Token::BIT_NOT: { |
| 3570 // smi check | 3570 // smi check |
| 3571 JumpTarget smi_label(this); | 3571 JumpTarget smi_label; |
| 3572 JumpTarget continue_label(this); | 3572 JumpTarget continue_label; |
| 3573 __ tst(r0, Operand(kSmiTagMask)); | 3573 __ tst(r0, Operand(kSmiTagMask)); |
| 3574 smi_label.Branch(eq); | 3574 smi_label.Branch(eq); |
| 3575 | 3575 |
| 3576 frame_->EmitPush(r0); | 3576 frame_->EmitPush(r0); |
| 3577 Result arg_count = allocator_->Allocate(r0); | 3577 Result arg_count = allocator_->Allocate(r0); |
| 3578 ASSERT(arg_count.is_valid()); | 3578 ASSERT(arg_count.is_valid()); |
| 3579 __ mov(arg_count.reg(), Operand(0)); // not counting receiver | 3579 __ mov(arg_count.reg(), Operand(0)); // not counting receiver |
| 3580 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_JS, &arg_count, 1); | 3580 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_JS, &arg_count, 1); |
| 3581 | 3581 |
| 3582 continue_label.Jump(); | 3582 continue_label.Jump(); |
| 3583 smi_label.Bind(); | 3583 smi_label.Bind(); |
| 3584 __ mvn(r0, Operand(r0)); | 3584 __ mvn(r0, Operand(r0)); |
| 3585 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag | 3585 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag |
| 3586 continue_label.Bind(); | 3586 continue_label.Bind(); |
| 3587 break; | 3587 break; |
| 3588 } | 3588 } |
| 3589 | 3589 |
| 3590 case Token::VOID: | 3590 case Token::VOID: |
| 3591 // since the stack top is cached in r0, popping and then | 3591 // since the stack top is cached in r0, popping and then |
| 3592 // pushing a value can be done by just writing to r0. | 3592 // pushing a value can be done by just writing to r0. |
| 3593 __ mov(r0, Operand(Factory::undefined_value())); | 3593 __ mov(r0, Operand(Factory::undefined_value())); |
| 3594 break; | 3594 break; |
| 3595 | 3595 |
| 3596 case Token::ADD: { | 3596 case Token::ADD: { |
| 3597 // Smi check. | 3597 // Smi check. |
| 3598 JumpTarget continue_label(this); | 3598 JumpTarget continue_label; |
| 3599 __ tst(r0, Operand(kSmiTagMask)); | 3599 __ tst(r0, Operand(kSmiTagMask)); |
| 3600 continue_label.Branch(eq); | 3600 continue_label.Branch(eq); |
| 3601 frame_->EmitPush(r0); | 3601 frame_->EmitPush(r0); |
| 3602 Result arg_count = allocator_->Allocate(r0); | 3602 Result arg_count = allocator_->Allocate(r0); |
| 3603 ASSERT(arg_count.is_valid()); | 3603 ASSERT(arg_count.is_valid()); |
| 3604 __ mov(arg_count.reg(), Operand(0)); // not counting receiver | 3604 __ mov(arg_count.reg(), Operand(0)); // not counting receiver |
| 3605 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, &arg_count, 1); | 3605 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, &arg_count, 1); |
| 3606 continue_label.Bind(); | 3606 continue_label.Bind(); |
| 3607 break; | 3607 break; |
| 3608 } | 3608 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3642 if (!is_postfix) { | 3642 if (!is_postfix) { |
| 3643 __ mov(r0, Operand(Smi::FromInt(0))); | 3643 __ mov(r0, Operand(Smi::FromInt(0))); |
| 3644 frame_->EmitPush(r0); | 3644 frame_->EmitPush(r0); |
| 3645 } | 3645 } |
| 3646 ASSERT(frame_->height() == original_height + 1); | 3646 ASSERT(frame_->height() == original_height + 1); |
| 3647 return; | 3647 return; |
| 3648 } | 3648 } |
| 3649 target.GetValueAndSpill(NOT_INSIDE_TYPEOF); | 3649 target.GetValueAndSpill(NOT_INSIDE_TYPEOF); |
| 3650 frame_->EmitPop(r0); | 3650 frame_->EmitPop(r0); |
| 3651 | 3651 |
| 3652 JumpTarget slow(this); | 3652 JumpTarget slow; |
| 3653 JumpTarget exit(this); | 3653 JumpTarget exit; |
| 3654 | 3654 |
| 3655 // Load the value (1) into register r1. | 3655 // Load the value (1) into register r1. |
| 3656 __ mov(r1, Operand(Smi::FromInt(1))); | 3656 __ mov(r1, Operand(Smi::FromInt(1))); |
| 3657 | 3657 |
| 3658 // Check for smi operand. | 3658 // Check for smi operand. |
| 3659 __ tst(r0, Operand(kSmiTagMask)); | 3659 __ tst(r0, Operand(kSmiTagMask)); |
| 3660 slow.Branch(ne); | 3660 slow.Branch(ne); |
| 3661 | 3661 |
| 3662 // Postfix: Store the old value as the result. | 3662 // Postfix: Store the old value as the result. |
| 3663 if (is_postfix) { | 3663 if (is_postfix) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3732 // produced by a && or || operator is not necessarily a boolean. | 3732 // produced by a && or || operator is not necessarily a boolean. |
| 3733 | 3733 |
| 3734 // NOTE: If the left hand side produces a materialized value (not in | 3734 // NOTE: If the left hand side produces a materialized value (not in |
| 3735 // the CC register), we force the right hand side to do the | 3735 // the CC register), we force the right hand side to do the |
| 3736 // same. This is necessary because we may have to branch to the exit | 3736 // same. This is necessary because we may have to branch to the exit |
| 3737 // after evaluating the left hand side (due to the shortcut | 3737 // after evaluating the left hand side (due to the shortcut |
| 3738 // semantics), but the compiler must (statically) know if the result | 3738 // semantics), but the compiler must (statically) know if the result |
| 3739 // of compiling the binary operation is materialized or not. | 3739 // of compiling the binary operation is materialized or not. |
| 3740 | 3740 |
| 3741 if (op == Token::AND) { | 3741 if (op == Token::AND) { |
| 3742 JumpTarget is_true(this); | 3742 JumpTarget is_true; |
| 3743 LoadConditionAndSpill(node->left(), | 3743 LoadConditionAndSpill(node->left(), |
| 3744 NOT_INSIDE_TYPEOF, | 3744 NOT_INSIDE_TYPEOF, |
| 3745 &is_true, | 3745 &is_true, |
| 3746 false_target(), | 3746 false_target(), |
| 3747 false); | 3747 false); |
| 3748 if (has_cc()) { | 3748 if (has_cc()) { |
| 3749 Branch(false, false_target()); | 3749 Branch(false, false_target()); |
| 3750 | 3750 |
| 3751 // Evaluate right side expression. | 3751 // Evaluate right side expression. |
| 3752 is_true.Bind(); | 3752 is_true.Bind(); |
| 3753 LoadConditionAndSpill(node->right(), | 3753 LoadConditionAndSpill(node->right(), |
| 3754 NOT_INSIDE_TYPEOF, | 3754 NOT_INSIDE_TYPEOF, |
| 3755 true_target(), | 3755 true_target(), |
| 3756 false_target(), | 3756 false_target(), |
| 3757 false); | 3757 false); |
| 3758 | 3758 |
| 3759 } else { | 3759 } else { |
| 3760 JumpTarget pop_and_continue(this); | 3760 JumpTarget pop_and_continue; |
| 3761 JumpTarget exit(this); | 3761 JumpTarget exit; |
| 3762 | 3762 |
| 3763 __ ldr(r0, frame_->Top()); // dup the stack top | 3763 __ ldr(r0, frame_->Top()); // dup the stack top |
| 3764 frame_->EmitPush(r0); | 3764 frame_->EmitPush(r0); |
| 3765 // Avoid popping the result if it converts to 'false' using the | 3765 // Avoid popping the result if it converts to 'false' using the |
| 3766 // standard ToBoolean() conversion as described in ECMA-262, | 3766 // standard ToBoolean() conversion as described in ECMA-262, |
| 3767 // section 9.2, page 30. | 3767 // section 9.2, page 30. |
| 3768 ToBoolean(&pop_and_continue, &exit); | 3768 ToBoolean(&pop_and_continue, &exit); |
| 3769 Branch(false, &exit); | 3769 Branch(false, &exit); |
| 3770 | 3770 |
| 3771 // Pop the result of evaluating the first part. | 3771 // Pop the result of evaluating the first part. |
| 3772 pop_and_continue.Bind(); | 3772 pop_and_continue.Bind(); |
| 3773 frame_->EmitPop(r0); | 3773 frame_->EmitPop(r0); |
| 3774 | 3774 |
| 3775 // Evaluate right side expression. | 3775 // Evaluate right side expression. |
| 3776 is_true.Bind(); | 3776 is_true.Bind(); |
| 3777 LoadAndSpill(node->right()); | 3777 LoadAndSpill(node->right()); |
| 3778 | 3778 |
| 3779 // Exit (always with a materialized value). | 3779 // Exit (always with a materialized value). |
| 3780 exit.Bind(); | 3780 exit.Bind(); |
| 3781 } | 3781 } |
| 3782 | 3782 |
| 3783 } else if (op == Token::OR) { | 3783 } else if (op == Token::OR) { |
| 3784 JumpTarget is_false(this); | 3784 JumpTarget is_false; |
| 3785 LoadConditionAndSpill(node->left(), | 3785 LoadConditionAndSpill(node->left(), |
| 3786 NOT_INSIDE_TYPEOF, | 3786 NOT_INSIDE_TYPEOF, |
| 3787 true_target(), | 3787 true_target(), |
| 3788 &is_false, | 3788 &is_false, |
| 3789 false); | 3789 false); |
| 3790 if (has_cc()) { | 3790 if (has_cc()) { |
| 3791 Branch(true, true_target()); | 3791 Branch(true, true_target()); |
| 3792 | 3792 |
| 3793 // Evaluate right side expression. | 3793 // Evaluate right side expression. |
| 3794 is_false.Bind(); | 3794 is_false.Bind(); |
| 3795 LoadConditionAndSpill(node->right(), | 3795 LoadConditionAndSpill(node->right(), |
| 3796 NOT_INSIDE_TYPEOF, | 3796 NOT_INSIDE_TYPEOF, |
| 3797 true_target(), | 3797 true_target(), |
| 3798 false_target(), | 3798 false_target(), |
| 3799 false); | 3799 false); |
| 3800 | 3800 |
| 3801 } else { | 3801 } else { |
| 3802 JumpTarget pop_and_continue(this); | 3802 JumpTarget pop_and_continue; |
| 3803 JumpTarget exit(this); | 3803 JumpTarget exit; |
| 3804 | 3804 |
| 3805 __ ldr(r0, frame_->Top()); | 3805 __ ldr(r0, frame_->Top()); |
| 3806 frame_->EmitPush(r0); | 3806 frame_->EmitPush(r0); |
| 3807 // Avoid popping the result if it converts to 'true' using the | 3807 // Avoid popping the result if it converts to 'true' using the |
| 3808 // standard ToBoolean() conversion as described in ECMA-262, | 3808 // standard ToBoolean() conversion as described in ECMA-262, |
| 3809 // section 9.2, page 30. | 3809 // section 9.2, page 30. |
| 3810 ToBoolean(&exit, &pop_and_continue); | 3810 ToBoolean(&exit, &pop_and_continue); |
| 3811 Branch(true, &exit); | 3811 Branch(true, &exit); |
| 3812 | 3812 |
| 3813 // Pop the result of evaluating the first part. | 3813 // Pop the result of evaluating the first part. |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4234 } else { | 4234 } else { |
| 4235 frame->CallRuntime(Runtime::kStoreContextSlot, 3); | 4235 frame->CallRuntime(Runtime::kStoreContextSlot, 3); |
| 4236 } | 4236 } |
| 4237 // Storing a variable must keep the (new) value on the expression | 4237 // Storing a variable must keep the (new) value on the expression |
| 4238 // stack. This is necessary for compiling assignment expressions. | 4238 // stack. This is necessary for compiling assignment expressions. |
| 4239 frame->EmitPush(r0); | 4239 frame->EmitPush(r0); |
| 4240 | 4240 |
| 4241 } else { | 4241 } else { |
| 4242 ASSERT(!slot->var()->is_dynamic()); | 4242 ASSERT(!slot->var()->is_dynamic()); |
| 4243 | 4243 |
| 4244 JumpTarget exit(cgen_); | 4244 JumpTarget exit; |
| 4245 if (init_state == CONST_INIT) { | 4245 if (init_state == CONST_INIT) { |
| 4246 ASSERT(slot->var()->mode() == Variable::CONST); | 4246 ASSERT(slot->var()->mode() == Variable::CONST); |
| 4247 // Only the first const initialization must be executed (the slot | 4247 // Only the first const initialization must be executed (the slot |
| 4248 // still contains 'the hole' value). When the assignment is | 4248 // still contains 'the hole' value). When the assignment is |
| 4249 // executed, the code is identical to a normal store (see below). | 4249 // executed, the code is identical to a normal store (see below). |
| 4250 Comment cmnt(masm, "[ Init const"); | 4250 Comment cmnt(masm, "[ Init const"); |
| 4251 __ ldr(r2, cgen_->SlotOperand(slot, r2)); | 4251 __ ldr(r2, cgen_->SlotOperand(slot, r2)); |
| 4252 __ cmp(r2, Operand(Factory::the_hole_value())); | 4252 __ cmp(r2, Operand(Factory::the_hole_value())); |
| 4253 exit.Branch(ne); | 4253 exit.Branch(ne); |
| 4254 } | 4254 } |
| (...skipping 925 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5180 __ mov(r2, Operand(0)); | 5180 __ mov(r2, Operand(0)); |
| 5181 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 5181 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 5182 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 5182 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
| 5183 RelocInfo::CODE_TARGET); | 5183 RelocInfo::CODE_TARGET); |
| 5184 } | 5184 } |
| 5185 | 5185 |
| 5186 | 5186 |
| 5187 #undef __ | 5187 #undef __ |
| 5188 | 5188 |
| 5189 } } // namespace v8::internal | 5189 } } // namespace v8::internal |
| OLD | NEW |