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 |