| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 | 74 |
| 75 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, | 75 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
| 76 bool is_eval) | 76 bool is_eval) |
| 77 : is_eval_(is_eval), | 77 : is_eval_(is_eval), |
| 78 script_(script), | 78 script_(script), |
| 79 deferred_(8), | 79 deferred_(8), |
| 80 masm_(new MacroAssembler(NULL, buffer_size)), | 80 masm_(new MacroAssembler(NULL, buffer_size)), |
| 81 scope_(NULL), | 81 scope_(NULL), |
| 82 frame_(NULL), | 82 frame_(NULL), |
| 83 allocator_(NULL), | 83 allocator_(NULL), |
| 84 cc_reg_(no_condition), | |
| 85 state_(NULL), | 84 state_(NULL), |
| 86 break_stack_height_(0), | 85 break_stack_height_(0), |
| 87 loop_nesting_(0), | 86 loop_nesting_(0), |
| 88 function_return_is_shadowed_(false), | 87 function_return_is_shadowed_(false), |
| 89 in_spilled_code_(false) { | 88 in_spilled_code_(false) { |
| 90 } | 89 } |
| 91 | 90 |
| 92 | 91 |
| 93 void CodeGenerator::SetFrame(VirtualFrame* new_frame, | 92 void CodeGenerator::SetFrame(VirtualFrame* new_frame, |
| 94 RegisterFile* non_frame_registers) { | 93 RegisterFile* non_frame_registers) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 ZoneList<Statement*>* body = fun->body(); | 131 ZoneList<Statement*>* body = fun->body(); |
| 133 | 132 |
| 134 // Initialize state. | 133 // Initialize state. |
| 135 ASSERT(scope_ == NULL); | 134 ASSERT(scope_ == NULL); |
| 136 scope_ = fun->scope(); | 135 scope_ = fun->scope(); |
| 137 ASSERT(allocator_ == NULL); | 136 ASSERT(allocator_ == NULL); |
| 138 RegisterAllocator register_allocator(this); | 137 RegisterAllocator register_allocator(this); |
| 139 allocator_ = ®ister_allocator; | 138 allocator_ = ®ister_allocator; |
| 140 ASSERT(frame_ == NULL); | 139 ASSERT(frame_ == NULL); |
| 141 frame_ = new VirtualFrame(this); | 140 frame_ = new VirtualFrame(this); |
| 142 cc_reg_ = no_condition; | |
| 143 function_return_.set_code_generator(this); | 141 function_return_.set_code_generator(this); |
| 144 function_return_is_shadowed_ = false; | 142 function_return_is_shadowed_ = false; |
| 145 set_in_spilled_code(false); | 143 set_in_spilled_code(false); |
| 146 | 144 |
| 147 // Adjust for function-level loop nesting. | 145 // Adjust for function-level loop nesting. |
| 148 loop_nesting_ += fun->loop_nesting(); | 146 loop_nesting_ += fun->loop_nesting(); |
| 149 | 147 |
| 150 { | 148 { |
| 151 CodeGenState state(this); | 149 CodeGenState state(this); |
| 152 | 150 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 } | 321 } |
| 324 | 322 |
| 325 // Adjust for function-level loop nesting. | 323 // Adjust for function-level loop nesting. |
| 326 loop_nesting_ -= fun->loop_nesting(); | 324 loop_nesting_ -= fun->loop_nesting(); |
| 327 | 325 |
| 328 // Code generation state must be reset. | 326 // Code generation state must be reset. |
| 329 ASSERT(state_ == NULL); | 327 ASSERT(state_ == NULL); |
| 330 ASSERT(loop_nesting() == 0); | 328 ASSERT(loop_nesting() == 0); |
| 331 ASSERT(!function_return_is_shadowed_); | 329 ASSERT(!function_return_is_shadowed_); |
| 332 function_return_.Unuse(); | 330 function_return_.Unuse(); |
| 333 ASSERT(!has_cc()); | |
| 334 DeleteFrame(); | 331 DeleteFrame(); |
| 335 | 332 |
| 336 // Process any deferred code using the register allocator. | 333 // Process any deferred code using the register allocator. |
| 337 ProcessDeferred(); | 334 ProcessDeferred(); |
| 338 | 335 |
| 339 // There is no need to delete the register allocator, it is a | 336 // There is no need to delete the register allocator, it is a |
| 340 // stack-allocated local. | 337 // stack-allocated local. |
| 341 allocator_ = NULL; | 338 allocator_ = NULL; |
| 342 scope_ = NULL; | 339 scope_ = NULL; |
| 343 } | 340 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 return ContextOperand(tmp, index); | 384 return ContextOperand(tmp, index); |
| 388 } | 385 } |
| 389 | 386 |
| 390 default: | 387 default: |
| 391 UNREACHABLE(); | 388 UNREACHABLE(); |
| 392 return Operand(eax); | 389 return Operand(eax); |
| 393 } | 390 } |
| 394 } | 391 } |
| 395 | 392 |
| 396 | 393 |
| 397 // Loads a value on TOS. If it is a boolean value, the result may have been | 394 // Loads a value on TOS. If the result is a boolean value it may have |
| 398 // (partially) translated into branches, or it may have set the condition | 395 // been translated into control flow to the true and/or false targets. |
| 399 // code register. If force_cc is set, the value is forced to set the | 396 // If force_control is true, control flow is forced and the function |
| 400 // condition code register and no value is pushed. If the condition code | 397 // exits without a valid frame. |
| 401 // register was set, has_cc() is true and cc_reg_ contains the condition to | |
| 402 // test for 'true'. | |
| 403 void CodeGenerator::LoadCondition(Expression* x, | 398 void CodeGenerator::LoadCondition(Expression* x, |
| 404 TypeofState typeof_state, | 399 TypeofState typeof_state, |
| 405 JumpTarget* true_target, | 400 JumpTarget* true_target, |
| 406 JumpTarget* false_target, | 401 JumpTarget* false_target, |
| 407 bool force_cc) { | 402 bool force_control) { |
| 408 ASSERT(!in_spilled_code()); | 403 ASSERT(!in_spilled_code()); |
| 409 ASSERT(!has_cc()); | |
| 410 #ifdef DEBUG | 404 #ifdef DEBUG |
| 411 int original_height = frame_->height(); | 405 int original_height = frame_->height(); |
| 412 #endif | 406 #endif |
| 413 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 407 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 414 Visit(x); | 408 Visit(x); |
| 415 } | 409 } |
| 416 | 410 |
| 417 if (force_cc && has_valid_frame() && !has_cc()) { | 411 if (force_control && has_valid_frame()) { |
| 418 // Convert the TOS value to a boolean in the condition code register. | 412 // Convert the TOS value to a boolean in the condition code register. |
| 419 ToBoolean(true_target, false_target); | 413 ToBoolean(true_target, false_target); |
| 420 } | 414 } |
| 421 | 415 |
| 422 ASSERT(!force_cc || frame_ == NULL || has_cc()); | 416 ASSERT(!(force_control && has_valid_frame())); |
| 423 ASSERT(!has_valid_frame() || | 417 ASSERT(!has_valid_frame() || frame_->height() == original_height + 1); |
| 424 (has_cc() && frame_->height() == original_height) || | |
| 425 (!has_cc() && frame_->height() == original_height + 1)); | |
| 426 } | 418 } |
| 427 | 419 |
| 428 | 420 |
| 429 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 421 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 430 #ifdef DEBUG | 422 #ifdef DEBUG |
| 431 int original_height = frame_->height(); | 423 int original_height = frame_->height(); |
| 432 #endif | 424 #endif |
| 433 ASSERT(!in_spilled_code()); | 425 ASSERT(!in_spilled_code()); |
| 434 JumpTarget true_target(this); | 426 JumpTarget true_target(this); |
| 435 JumpTarget false_target(this); | 427 JumpTarget false_target(this); |
| 436 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 428 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 437 | 429 |
| 438 if (has_cc()) { | |
| 439 ASSERT(has_valid_frame()); | |
| 440 VirtualFrame::SpilledScope spilled_scope(this); | |
| 441 // Convert cc_reg_ into a boolean value. | |
| 442 JumpTarget loaded(this); | |
| 443 JumpTarget materialize_true(this); | |
| 444 Condition cc = cc_reg_; | |
| 445 cc_reg_ = no_condition; | |
| 446 materialize_true.Branch(cc); | |
| 447 frame_->EmitPush(Immediate(Factory::false_value())); | |
| 448 loaded.Jump(); | |
| 449 materialize_true.Bind(); | |
| 450 frame_->EmitPush(Immediate(Factory::true_value())); | |
| 451 loaded.Bind(); | |
| 452 } | |
| 453 | |
| 454 if (true_target.is_linked() || false_target.is_linked()) { | 430 if (true_target.is_linked() || false_target.is_linked()) { |
| 455 // We have at least one condition value that has been "translated" into | 431 // We have at least one condition value that has been "translated" into |
| 456 // a branch, thus it needs to be loaded explicitly. | 432 // a branch, thus it needs to be loaded explicitly. |
| 457 JumpTarget loaded(this); | 433 JumpTarget loaded(this); |
| 458 if (has_valid_frame()) { | 434 if (has_valid_frame()) { |
| 459 loaded.Jump(); // Don't lose the current TOS. | 435 loaded.Jump(); // Don't lose the current TOS. |
| 460 } | 436 } |
| 461 bool both = true_target.is_linked() && false_target.is_linked(); | 437 bool both = true_target.is_linked() && false_target.is_linked(); |
| 462 // Load "true" if necessary. | 438 // Load "true" if necessary. |
| 463 if (true_target.is_linked()) { | 439 if (true_target.is_linked()) { |
| 464 true_target.Bind(); | 440 true_target.Bind(); |
| 465 VirtualFrame::SpilledScope spilled_scope(this); | 441 VirtualFrame::SpilledScope spilled_scope(this); |
| 466 frame_->EmitPush(Immediate(Factory::true_value())); | 442 frame_->EmitPush(Immediate(Factory::true_value())); |
| 467 } | 443 } |
| 468 // If both "true" and "false" need to be reincarnated jump across the | 444 // If both "true" and "false" need to be reincarnated jump across the |
| 469 // code for "false". | 445 // code for "false". |
| 470 if (both) { | 446 if (both) { |
| 471 loaded.Jump(); | 447 loaded.Jump(); |
| 472 } | 448 } |
| 473 // Load "false" if necessary. | 449 // Load "false" if necessary. |
| 474 if (false_target.is_linked()) { | 450 if (false_target.is_linked()) { |
| 475 false_target.Bind(); | 451 false_target.Bind(); |
| 476 VirtualFrame::SpilledScope spilled_scope(this); | 452 VirtualFrame::SpilledScope spilled_scope(this); |
| 477 frame_->EmitPush(Immediate(Factory::false_value())); | 453 frame_->EmitPush(Immediate(Factory::false_value())); |
| 478 } | 454 } |
| 479 // A value is loaded on all paths reaching this point. | 455 // A value is loaded on all paths reaching this point. |
| 480 loaded.Bind(); | 456 loaded.Bind(); |
| 481 } | 457 } |
| 482 ASSERT(has_valid_frame()); | 458 ASSERT(has_valid_frame()); |
| 483 ASSERT(!has_cc()); | |
| 484 ASSERT(frame_->height() == original_height + 1); | 459 ASSERT(frame_->height() == original_height + 1); |
| 485 } | 460 } |
| 486 | 461 |
| 487 | 462 |
| 488 void CodeGenerator::LoadGlobal() { | 463 void CodeGenerator::LoadGlobal() { |
| 489 if (in_spilled_code()) { | 464 if (in_spilled_code()) { |
| 490 frame_->EmitPush(GlobalObject()); | 465 frame_->EmitPush(GlobalObject()); |
| 491 } else { | 466 } else { |
| 492 Result temp = allocator_->Allocate(); | 467 Result temp = allocator_->Allocate(); |
| 493 __ mov(temp.reg(), GlobalObject()); | 468 __ mov(temp.reg(), GlobalObject()); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 false_target->Branch(zero); | 612 false_target->Branch(zero); |
| 638 __ test(value.reg(), Immediate(kSmiTagMask)); | 613 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 639 true_target->Branch(zero); | 614 true_target->Branch(zero); |
| 640 | 615 |
| 641 // Call the stub for all other cases. | 616 // Call the stub for all other cases. |
| 642 frame_->Push(&value); // Undo the Pop() from above. | 617 frame_->Push(&value); // Undo the Pop() from above. |
| 643 ToBooleanStub stub; | 618 ToBooleanStub stub; |
| 644 Result temp = frame_->CallStub(&stub, 1); | 619 Result temp = frame_->CallStub(&stub, 1); |
| 645 // Convert the result to a condition code. | 620 // Convert the result to a condition code. |
| 646 __ test(temp.reg(), Operand(temp.reg())); | 621 __ test(temp.reg(), Operand(temp.reg())); |
| 647 | 622 temp.Unuse(); |
| 648 ASSERT(not_equal == not_zero); | 623 true_target->Branch(not_equal); |
| 649 cc_reg_ = not_equal; | 624 false_target->Jump(); |
| 650 } | 625 } |
| 651 | 626 |
| 652 | 627 |
| 653 class FloatingPointHelper : public AllStatic { | 628 class FloatingPointHelper : public AllStatic { |
| 654 public: | 629 public: |
| 655 // Code pattern for loading floating point values. Input values must | 630 // Code pattern for loading floating point values. Input values must |
| 656 // be either smi or heap number objects (fp values). Requirements: | 631 // be either smi or heap number objects (fp values). Requirements: |
| 657 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as | 632 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as |
| 658 // floating point numbers on FPU stack. | 633 // floating point numbers on FPU stack. |
| 659 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); | 634 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); |
| (...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1198 #ifdef DEBUG | 1173 #ifdef DEBUG |
| 1199 void Print() { | 1174 void Print() { |
| 1200 PrintF("CompareStub (cc %d), (strict %s)\n", | 1175 PrintF("CompareStub (cc %d), (strict %s)\n", |
| 1201 static_cast<int>(cc_), | 1176 static_cast<int>(cc_), |
| 1202 strict_ ? "true" : "false"); | 1177 strict_ ? "true" : "false"); |
| 1203 } | 1178 } |
| 1204 #endif | 1179 #endif |
| 1205 }; | 1180 }; |
| 1206 | 1181 |
| 1207 | 1182 |
| 1208 void CodeGenerator::Comparison(Condition cc, bool strict) { | 1183 void CodeGenerator::Comparison(Condition cc, |
| 1184 bool strict, |
| 1185 JumpTarget* true_target, |
| 1186 JumpTarget* false_target) { |
| 1209 // Strict only makes sense for equality comparisons. | 1187 // Strict only makes sense for equality comparisons. |
| 1210 ASSERT(!strict || cc == equal); | 1188 ASSERT(!strict || cc == equal); |
| 1211 | 1189 |
| 1212 Result left_side(this); | 1190 Result left_side(this); |
| 1213 Result right_side(this); | 1191 Result right_side(this); |
| 1214 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1192 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1215 if (cc == greater || cc == less_equal) { | 1193 if (cc == greater || cc == less_equal) { |
| 1216 cc = ReverseCondition(cc); | 1194 cc = ReverseCondition(cc); |
| 1217 left_side = frame_->Pop(); | 1195 left_side = frame_->Pop(); |
| 1218 right_side = frame_->Pop(); | 1196 right_side = frame_->Pop(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1284 } | 1262 } |
| 1285 __ cmp(left_side.reg(), Operand(right_side.reg())); | 1263 __ cmp(left_side.reg(), Operand(right_side.reg())); |
| 1286 right_side.Unuse(); | 1264 right_side.Unuse(); |
| 1287 left_side.Unuse(); | 1265 left_side.Unuse(); |
| 1288 __ setcc(cc, answer.reg()); | 1266 __ setcc(cc, answer.reg()); |
| 1289 __ and_(Operand(answer.reg()), Immediate(1)); | 1267 __ and_(Operand(answer.reg()), Immediate(1)); |
| 1290 | 1268 |
| 1291 done.Bind(&answer); | 1269 done.Bind(&answer); |
| 1292 answer.ToRegister(); | 1270 answer.ToRegister(); |
| 1293 __ test(answer.reg(), Operand(answer.reg())); | 1271 __ test(answer.reg(), Operand(answer.reg())); |
| 1294 cc_reg_ = not_zero; | 1272 answer.Unuse(); |
| 1273 true_target->Branch(not_zero); |
| 1274 false_target->Jump(); |
| 1295 } | 1275 } |
| 1296 | 1276 |
| 1297 | 1277 |
| 1298 class DeferredSmiComparison: public DeferredCode { | 1278 class DeferredSmiComparison: public DeferredCode { |
| 1299 public: | 1279 public: |
| 1300 DeferredSmiComparison(CodeGenerator* generator, | 1280 DeferredSmiComparison(CodeGenerator* generator, |
| 1301 Condition cc, | 1281 Condition cc, |
| 1302 bool strict, | 1282 bool strict, |
| 1303 int int_value) : | 1283 int int_value) : |
| 1304 DeferredCode(generator), | 1284 DeferredCode(generator), |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1367 } | 1347 } |
| 1368 // Test smi equality and comparison by signed int comparison. | 1348 // Test smi equality and comparison by signed int comparison. |
| 1369 __ cmp(Operand(comparee.reg()), Immediate(value)); | 1349 __ cmp(Operand(comparee.reg()), Immediate(value)); |
| 1370 comparee.Unuse(); | 1350 comparee.Unuse(); |
| 1371 __ setcc(cc, flag.reg()); | 1351 __ setcc(cc, flag.reg()); |
| 1372 __ and_(Operand(flag.reg()), Immediate(1)); | 1352 __ and_(Operand(flag.reg()), Immediate(1)); |
| 1373 | 1353 |
| 1374 deferred->exit()->Bind(&flag); | 1354 deferred->exit()->Bind(&flag); |
| 1375 flag.ToRegister(); | 1355 flag.ToRegister(); |
| 1376 __ test(flag.reg(), Operand(flag.reg())); | 1356 __ test(flag.reg(), Operand(flag.reg())); |
| 1377 cc_reg_ = not_zero; | 1357 flag.Unuse(); |
| 1358 true_target()->Branch(not_zero); |
| 1359 false_target()->Jump(); |
| 1378 } | 1360 } |
| 1379 | 1361 |
| 1380 | 1362 |
| 1381 class CallFunctionStub: public CodeStub { | 1363 class CallFunctionStub: public CodeStub { |
| 1382 public: | 1364 public: |
| 1383 explicit CallFunctionStub(int argc) : argc_(argc) { } | 1365 explicit CallFunctionStub(int argc) : argc_(argc) { } |
| 1384 | 1366 |
| 1385 void Generate(MacroAssembler* masm); | 1367 void Generate(MacroAssembler* masm); |
| 1386 | 1368 |
| 1387 private: | 1369 private: |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1412 // Use the shared code stub to call the function. | 1394 // Use the shared code stub to call the function. |
| 1413 CallFunctionStub call_function(arg_count); | 1395 CallFunctionStub call_function(arg_count); |
| 1414 Result answer = frame_->CallStub(&call_function, arg_count + 1); | 1396 Result answer = frame_->CallStub(&call_function, arg_count + 1); |
| 1415 // Restore context and replace function on the stack with the | 1397 // Restore context and replace function on the stack with the |
| 1416 // result of the stub invocation. | 1398 // result of the stub invocation. |
| 1417 frame_->RestoreContextRegister(); | 1399 frame_->RestoreContextRegister(); |
| 1418 frame_->SetElementAt(0, &answer); | 1400 frame_->SetElementAt(0, &answer); |
| 1419 } | 1401 } |
| 1420 | 1402 |
| 1421 | 1403 |
| 1422 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { | |
| 1423 ASSERT(has_cc()); | |
| 1424 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | |
| 1425 cc_reg_ = no_condition; | |
| 1426 target->Branch(cc); | |
| 1427 } | |
| 1428 | |
| 1429 | |
| 1430 void CodeGenerator::CheckStack() { | 1404 void CodeGenerator::CheckStack() { |
| 1431 if (FLAG_check_stack) { | 1405 if (FLAG_check_stack) { |
| 1432 JumpTarget stack_is_ok(this); | 1406 JumpTarget stack_is_ok(this); |
| 1433 StackCheckStub stub; | 1407 StackCheckStub stub; |
| 1434 ExternalReference stack_guard_limit = | 1408 ExternalReference stack_guard_limit = |
| 1435 ExternalReference::address_of_stack_guard_limit(); | 1409 ExternalReference::address_of_stack_guard_limit(); |
| 1436 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); | 1410 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); |
| 1437 stack_is_ok.Branch(above_equal, taken); | 1411 stack_is_ok.Branch(above_equal, taken); |
| 1438 // The stack check can trigger the debugger. Before calling it, all | 1412 // The stack check can trigger the debugger. Before calling it, all |
| 1439 // values including constants must be spilled to the frame. | 1413 // values including constants must be spilled to the frame. |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1566 // are present or not. | 1540 // are present or not. |
| 1567 bool has_then_stm = node->HasThenStatement(); | 1541 bool has_then_stm = node->HasThenStatement(); |
| 1568 bool has_else_stm = node->HasElseStatement(); | 1542 bool has_else_stm = node->HasElseStatement(); |
| 1569 | 1543 |
| 1570 CodeForStatement(node); | 1544 CodeForStatement(node); |
| 1571 JumpTarget exit(this); | 1545 JumpTarget exit(this); |
| 1572 if (has_then_stm && has_else_stm) { | 1546 if (has_then_stm && has_else_stm) { |
| 1573 JumpTarget then(this); | 1547 JumpTarget then(this); |
| 1574 JumpTarget else_(this); | 1548 JumpTarget else_(this); |
| 1575 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1549 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 1576 if (has_valid_frame()) { | |
| 1577 // We have fallen through from the condition (with a value in cc_reg). | |
| 1578 // Emit a branch if false around the then block and compile both | |
| 1579 // blocks. | |
| 1580 Branch(false, &else_); | |
| 1581 } | |
| 1582 if (then.is_linked()) { | 1550 if (then.is_linked()) { |
| 1583 then.Bind(); | 1551 then.Bind(); |
| 1584 } | |
| 1585 if (has_valid_frame()) { | |
| 1586 // We have fallen through from the condition or reached here by a | |
| 1587 // direct jump to the then target. | |
| 1588 Visit(node->then_statement()); | 1552 Visit(node->then_statement()); |
| 1589 } | 1553 if (has_valid_frame() && else_.is_linked()) { |
| 1590 if (has_valid_frame() && else_.is_linked()) { | 1554 // We have fallen through from the then block and we need to compile |
| 1591 // We have fallen through from the then block and we need to compile | 1555 // the else block. Emit an unconditional jump around it. |
| 1592 // the else block. Emit an unconditional jump around it. | 1556 exit.Jump(); |
| 1593 exit.Jump(); | 1557 } |
| 1594 } | 1558 } |
| 1595 if (else_.is_linked()) { | 1559 if (else_.is_linked()) { |
| 1596 else_.Bind(); | 1560 else_.Bind(); |
| 1597 Visit(node->else_statement()); | 1561 Visit(node->else_statement()); |
| 1598 } | 1562 } |
| 1599 | 1563 |
| 1600 } else if (has_then_stm) { | 1564 } else if (has_then_stm) { |
| 1601 ASSERT(!has_else_stm); | 1565 ASSERT(!has_else_stm); |
| 1602 JumpTarget then(this); | 1566 JumpTarget then(this); |
| 1603 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); | 1567 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); |
| 1604 if (has_valid_frame()) { | |
| 1605 // We have fallen through from the condition (with a value in cc_reg). | |
| 1606 // Emit a branch if false around the then block. | |
| 1607 Branch(false, &exit); | |
| 1608 } | |
| 1609 if (then.is_linked()) { | 1568 if (then.is_linked()) { |
| 1610 then.Bind(); | 1569 then.Bind(); |
| 1611 } | |
| 1612 if (has_valid_frame()) { | |
| 1613 // We have fallen through from the condition or reached here by a | |
| 1614 // direct jump to the then target. | |
| 1615 Visit(node->then_statement()); | 1570 Visit(node->then_statement()); |
| 1616 } | 1571 } |
| 1617 | 1572 |
| 1618 } else if (has_else_stm) { | 1573 } else if (has_else_stm) { |
| 1619 ASSERT(!has_then_stm); | 1574 ASSERT(!has_then_stm); |
| 1620 JumpTarget else_(this); | 1575 JumpTarget else_(this); |
| 1621 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); | 1576 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); |
| 1622 if (has_valid_frame()) { | |
| 1623 // We have fallen through from the condition (with a value in cc_reg). | |
| 1624 // Emit a branch if true around the else block. | |
| 1625 Branch(true, &exit); | |
| 1626 } | |
| 1627 if (else_.is_linked()) { | 1577 if (else_.is_linked()) { |
| 1628 else_.Bind(); | 1578 else_.Bind(); |
| 1629 } | |
| 1630 if (has_valid_frame()) { | |
| 1631 // We have fallen through from the condition or reached here by a | |
| 1632 // direct jump to the else target. | |
| 1633 Visit(node->else_statement()); | 1579 Visit(node->else_statement()); |
| 1634 } | 1580 } |
| 1635 | 1581 |
| 1636 } else { | 1582 } else { |
| 1637 ASSERT(!has_then_stm && !has_else_stm); | 1583 ASSERT(!has_then_stm && !has_else_stm); |
| 1638 // We only care about the condition's side effects (not its value or | 1584 // We only care about the condition's side effects (not its value |
| 1639 // control flow effect). LoadCondition is called without forcing a | 1585 // or control flow effect). LoadCondition is called without |
| 1640 // value into cc_reg. | 1586 // forcing control flow. |
| 1641 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1587 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
| 1642 if (has_valid_frame()) { | 1588 if (has_valid_frame()) { |
| 1643 // Control flow can fall off the end of the condition. We discard its | 1589 // Control flow can fall off the end of the condition with a |
| 1644 // value, which may be in cc_reg or else on top of the virtual frame. | 1590 // value on the frame. |
| 1645 if (has_cc()) { | 1591 frame_->Drop(); |
| 1646 cc_reg_ = no_condition; | |
| 1647 } else { | |
| 1648 frame_->Drop(); | |
| 1649 } | |
| 1650 } | 1592 } |
| 1651 } | 1593 } |
| 1652 | 1594 |
| 1653 if (exit.is_linked()) { | 1595 if (exit.is_linked()) { |
| 1654 exit.Bind(); | 1596 exit.Bind(); |
| 1655 } | 1597 } |
| 1656 } | 1598 } |
| 1657 | 1599 |
| 1658 | 1600 |
| 1659 void CodeGenerator::CleanStack(int num_bytes) { | 1601 void CodeGenerator::CleanStack(int num_bytes) { |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1899 Comment cmnt(masm_, "[ Case clause"); | 1841 Comment cmnt(masm_, "[ Case clause"); |
| 1900 // Label and compile the test. | 1842 // Label and compile the test. |
| 1901 if (next_test.is_linked()) { | 1843 if (next_test.is_linked()) { |
| 1902 // Recycle the same label for each test. | 1844 // Recycle the same label for each test. |
| 1903 next_test.Bind(); | 1845 next_test.Bind(); |
| 1904 next_test.Unuse(); | 1846 next_test.Unuse(); |
| 1905 } | 1847 } |
| 1906 // Duplicate the switch value. | 1848 // Duplicate the switch value. |
| 1907 frame_->Dup(); | 1849 frame_->Dup(); |
| 1908 Load(clause->label()); | 1850 Load(clause->label()); |
| 1909 Comparison(equal, true); | 1851 JumpTarget enter_body(this); |
| 1910 Branch(false, &next_test); | 1852 Comparison(equal, true, &enter_body, &next_test); |
| 1911 | 1853 |
| 1912 // Before entering the body from the test remove the switch value from | 1854 // Before entering the body from the test remove the switch value from |
| 1913 // the frame. | 1855 // the frame. |
| 1856 enter_body.Bind(); |
| 1914 frame_->Drop(); | 1857 frame_->Drop(); |
| 1915 | 1858 |
| 1916 // Label the body so that fall through is enabled. | 1859 // Label the body so that fall through is enabled. |
| 1917 if (i > 0 && cases->at(i - 1)->is_default()) { | 1860 if (i > 0 && cases->at(i - 1)->is_default()) { |
| 1918 // The previous case was the default. This will be the target of a | 1861 // The previous case was the default. This will be the target of a |
| 1919 // possible backward edge. | 1862 // possible backward edge. |
| 1920 default_exit.Bind(); | 1863 default_exit.Bind(); |
| 1921 } else if (fall_through.is_linked()) { | 1864 } else if (fall_through.is_linked()) { |
| 1922 // Recycle the same label for each fall through except for the default | 1865 // Recycle the same label for each fall through except for the default |
| 1923 // case. | 1866 // case. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2024 } else { | 1967 } else { |
| 2025 ASSERT(info == DONT_KNOW); | 1968 ASSERT(info == DONT_KNOW); |
| 2026 // We have to compile the test expression if it can be reached by | 1969 // We have to compile the test expression if it can be reached by |
| 2027 // control flow falling out of the body or via continue. | 1970 // control flow falling out of the body or via continue. |
| 2028 if (node->continue_target()->is_linked()) { | 1971 if (node->continue_target()->is_linked()) { |
| 2029 node->continue_target()->Bind(); | 1972 node->continue_target()->Bind(); |
| 2030 } | 1973 } |
| 2031 if (has_valid_frame()) { | 1974 if (has_valid_frame()) { |
| 2032 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 1975 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 2033 &body, node->break_target(), true); | 1976 &body, node->break_target(), true); |
| 2034 // An invalid frame here indicates that control flow did not fall | |
| 2035 // out of the test expression. | |
| 2036 if (has_valid_frame()) { | |
| 2037 Branch(true, &body); | |
| 2038 } | |
| 2039 } | 1977 } |
| 2040 } | 1978 } |
| 2041 break; | 1979 break; |
| 2042 } | 1980 } |
| 2043 | 1981 |
| 2044 case LoopStatement::WHILE_LOOP: { | 1982 case LoopStatement::WHILE_LOOP: { |
| 2045 IncrementLoopNesting(); | 1983 IncrementLoopNesting(); |
| 2046 | 1984 |
| 2047 // If the test is never true and has no side effects there is no need | 1985 // If the test is never true and has no side effects there is no need |
| 2048 // to compile the test or body. | 1986 // to compile the test or body. |
| 2049 if (info == ALWAYS_FALSE) break; | 1987 if (info == ALWAYS_FALSE) break; |
| 2050 | 1988 |
| 2051 // Label the top of the loop with the continue target for the backward | 1989 // Label the top of the loop with the continue target for the backward |
| 2052 // CFG edge. | 1990 // CFG edge. |
| 2053 node->continue_target()->Bind(); | 1991 node->continue_target()->Bind(); |
| 2054 | 1992 |
| 2055 // If the test is always true and has no side effects there is no need | 1993 // If the test is always true and has no side effects there is no need |
| 2056 // to compile it. We only compile the test when we do not know its | 1994 // to compile it. We only compile the test when we do not know its |
| 2057 // outcome or it may have side effects. | 1995 // outcome or it may have side effects. |
| 2058 if (info == DONT_KNOW) { | 1996 if (info == DONT_KNOW) { |
| 2059 JumpTarget body(this); | 1997 JumpTarget body(this); |
| 2060 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 1998 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 2061 &body, node->break_target(), true); | 1999 &body, node->break_target(), true); |
| 2062 // An invalid frame indicates that control did not fall out of the | |
| 2063 // test expression. | |
| 2064 if (has_valid_frame()) { | |
| 2065 Branch(false, node->break_target()); | |
| 2066 } | |
| 2067 if (body.is_linked()) { | 2000 if (body.is_linked()) { |
| 2068 body.Bind(); | 2001 body.Bind(); |
| 2069 } | 2002 } |
| 2070 } | 2003 } |
| 2071 | 2004 |
| 2072 if (has_valid_frame()) { | 2005 if (has_valid_frame()) { |
| 2073 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2006 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2074 Visit(node->body()); | 2007 Visit(node->body()); |
| 2075 | 2008 |
| 2076 // If control flow can fall out of the body, jump back to the top. | 2009 // If control flow can fall out of the body, jump back to the top. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2100 loop.Bind(); | 2033 loop.Bind(); |
| 2101 } | 2034 } |
| 2102 | 2035 |
| 2103 // If the test is always true and has no side effects there is no need | 2036 // If the test is always true and has no side effects there is no need |
| 2104 // to compile it. We only compile the test when we do not know its | 2037 // to compile it. We only compile the test when we do not know its |
| 2105 // outcome or it has side effects. | 2038 // outcome or it has side effects. |
| 2106 if (info == DONT_KNOW) { | 2039 if (info == DONT_KNOW) { |
| 2107 JumpTarget body(this); | 2040 JumpTarget body(this); |
| 2108 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 2041 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 2109 &body, node->break_target(), true); | 2042 &body, node->break_target(), true); |
| 2110 if (has_valid_frame()) { | |
| 2111 Branch(false, node->break_target()); | |
| 2112 } | |
| 2113 if (body.is_linked()) { | 2043 if (body.is_linked()) { |
| 2114 body.Bind(); | 2044 body.Bind(); |
| 2115 } | 2045 } |
| 2116 } | 2046 } |
| 2117 | 2047 |
| 2118 if (has_valid_frame()) { | 2048 if (has_valid_frame()) { |
| 2119 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2049 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2120 Visit(node->body()); | 2050 Visit(node->body()); |
| 2121 | 2051 |
| 2122 if (node->next() == NULL) { | 2052 if (node->next() == NULL) { |
| (...skipping 562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2685 InstantiateBoilerplate(node->boilerplate()); | 2615 InstantiateBoilerplate(node->boilerplate()); |
| 2686 } | 2616 } |
| 2687 | 2617 |
| 2688 | 2618 |
| 2689 void CodeGenerator::VisitConditional(Conditional* node) { | 2619 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2690 Comment cmnt(masm_, "[ Conditional"); | 2620 Comment cmnt(masm_, "[ Conditional"); |
| 2691 JumpTarget then(this); | 2621 JumpTarget then(this); |
| 2692 JumpTarget else_(this); | 2622 JumpTarget else_(this); |
| 2693 JumpTarget exit(this); | 2623 JumpTarget exit(this); |
| 2694 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 2624 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 2695 if (has_valid_frame()) { | |
| 2696 Branch(false, &else_); | |
| 2697 } | |
| 2698 if (then.is_linked()) { | 2625 if (then.is_linked()) { |
| 2699 then.Bind(); | 2626 then.Bind(); |
| 2627 Load(node->then_expression(), typeof_state()); |
| 2628 if (else_.is_linked()) { |
| 2629 exit.Jump(); |
| 2630 } |
| 2700 } | 2631 } |
| 2701 if (has_valid_frame()) { | 2632 |
| 2702 Load(node->then_expression(), typeof_state()); | |
| 2703 exit.Jump(); | |
| 2704 } | |
| 2705 if (else_.is_linked()) { | 2633 if (else_.is_linked()) { |
| 2706 else_.Bind(); | 2634 else_.Bind(); |
| 2707 Load(node->else_expression(), typeof_state()); | 2635 Load(node->else_expression(), typeof_state()); |
| 2708 } | 2636 } |
| 2709 exit.Bind(); | 2637 |
| 2638 if (exit.is_linked()) { |
| 2639 exit.Bind(); |
| 2640 } |
| 2710 } | 2641 } |
| 2711 | 2642 |
| 2712 | 2643 |
| 2713 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2644 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2714 if (slot->type() == Slot::LOOKUP) { | 2645 if (slot->type() == Slot::LOOKUP) { |
| 2715 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2646 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2716 | 2647 |
| 2717 // For now, just do a runtime call. | 2648 // For now, just do a runtime call. |
| 2718 frame_->Push(esi); | 2649 frame_->Push(esi); |
| 2719 frame_->Push(slot->var()->name()); | 2650 frame_->Push(slot->var()->name()); |
| (...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3451 frame_->RestoreContextRegister(); | 3382 frame_->RestoreContextRegister(); |
| 3452 __ mov(frame_->Top(), eax); | 3383 __ mov(frame_->Top(), eax); |
| 3453 } | 3384 } |
| 3454 | 3385 |
| 3455 | 3386 |
| 3456 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 3387 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 3457 ASSERT(args->length() == 1); | 3388 ASSERT(args->length() == 1); |
| 3458 LoadAndSpill(args->at(0)); | 3389 LoadAndSpill(args->at(0)); |
| 3459 frame_->EmitPop(eax); | 3390 frame_->EmitPop(eax); |
| 3460 __ test(eax, Immediate(kSmiTagMask)); | 3391 __ test(eax, Immediate(kSmiTagMask)); |
| 3461 cc_reg_ = zero; | 3392 true_target()->Branch(zero); |
| 3393 false_target()->Jump(); |
| 3462 } | 3394 } |
| 3463 | 3395 |
| 3464 | 3396 |
| 3465 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { | 3397 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { |
| 3466 // Conditionally generate a log call. | 3398 // Conditionally generate a log call. |
| 3467 // Args: | 3399 // Args: |
| 3468 // 0 (literal string): The type of logging (corresponds to the flags). | 3400 // 0 (literal string): The type of logging (corresponds to the flags). |
| 3469 // This is used to determine whether or not to generate the log call. | 3401 // This is used to determine whether or not to generate the log call. |
| 3470 // 1 (string): Format string. Access the string at argument index 2 | 3402 // 1 (string): Format string. Access the string at argument index 2 |
| 3471 // with '%2s' (see Logger::LogRuntime for all the formats). | 3403 // with '%2s' (see Logger::LogRuntime for all the formats). |
| 3472 // 2 (array): Arguments to the format string. | 3404 // 2 (array): Arguments to the format string. |
| 3473 ASSERT_EQ(args->length(), 3); | 3405 ASSERT_EQ(args->length(), 3); |
| 3474 #ifdef ENABLE_LOGGING_AND_PROFILING | 3406 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 3475 if (ShouldGenerateLog(args->at(0))) { | 3407 if (ShouldGenerateLog(args->at(0))) { |
| 3476 LoadAndSpill(args->at(1)); | 3408 LoadAndSpill(args->at(1)); |
| 3477 LoadAndSpill(args->at(2)); | 3409 LoadAndSpill(args->at(2)); |
| 3478 frame_->CallRuntime(Runtime::kLog, 2); | 3410 frame_->CallRuntime(Runtime::kLog, 2); |
| 3479 } | 3411 } |
| 3480 #endif | 3412 #endif |
| 3481 // Finally, we're expected to leave a value on the top of the stack. | 3413 // Finally, we're expected to leave a value on the top of the stack. |
| 3482 frame_->EmitPush(Immediate(Factory::undefined_value())); | 3414 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3483 } | 3415 } |
| 3484 | 3416 |
| 3485 | 3417 |
| 3486 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3418 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 3487 ASSERT(args->length() == 1); | 3419 ASSERT(args->length() == 1); |
| 3488 LoadAndSpill(args->at(0)); | 3420 LoadAndSpill(args->at(0)); |
| 3489 frame_->EmitPop(eax); | 3421 frame_->EmitPop(eax); |
| 3490 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); | 3422 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 3491 cc_reg_ = zero; | 3423 true_target()->Branch(zero); |
| 3424 false_target()->Jump(); |
| 3492 } | 3425 } |
| 3493 | 3426 |
| 3494 | 3427 |
| 3495 // This generates code that performs a charCodeAt() call or returns | 3428 // This generates code that performs a charCodeAt() call or returns |
| 3496 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3429 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 3497 // It can handle flat and sliced strings, 8 and 16 bit characters and | 3430 // It can handle flat and sliced strings, 8 and 16 bit characters and |
| 3498 // cons strings where the answer is found in the left hand branch of the | 3431 // cons strings where the answer is found in the left hand branch of the |
| 3499 // cons. The slow case will flatten the string, which will ensure that | 3432 // cons. The slow case will flatten the string, which will ensure that |
| 3500 // the answer is in the left hand side the next time around. | 3433 // the answer is in the left hand side the next time around. |
| 3501 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3434 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3605 slow_case.Bind(); | 3538 slow_case.Bind(); |
| 3606 frame_->EmitPush(Immediate(Factory::undefined_value())); | 3539 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3607 | 3540 |
| 3608 end.Bind(); | 3541 end.Bind(); |
| 3609 } | 3542 } |
| 3610 | 3543 |
| 3611 | 3544 |
| 3612 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3545 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3613 ASSERT(args->length() == 1); | 3546 ASSERT(args->length() == 1); |
| 3614 LoadAndSpill(args->at(0)); | 3547 LoadAndSpill(args->at(0)); |
| 3615 Label answer; | |
| 3616 // We need the CC bits to come out as not_equal in the case where the | 3548 // We need the CC bits to come out as not_equal in the case where the |
| 3617 // object is a smi. This can't be done with the usual test opcode so | 3549 // object is a smi. This can't be done with the usual test opcode so |
| 3618 // we copy the object to ecx and do some destructive ops on it that | 3550 // we copy the object to ecx and do some destructive ops on it that |
| 3619 // result in the right CC bits. | 3551 // result in the right CC bits. |
| 3620 frame_->EmitPop(eax); | 3552 frame_->EmitPop(eax); |
| 3621 __ mov(ecx, Operand(eax)); | 3553 __ mov(ecx, Operand(eax)); |
| 3622 __ and_(ecx, kSmiTagMask); | 3554 __ and_(ecx, kSmiTagMask); |
| 3623 __ xor_(ecx, kSmiTagMask); | 3555 __ xor_(ecx, kSmiTagMask); |
| 3624 __ j(not_equal, &answer, not_taken); | 3556 false_target()->Branch(not_equal); |
| 3625 // It is a heap object - get map. | 3557 // It is a heap object - get map. |
| 3626 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 3558 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3627 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); | 3559 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); |
| 3628 // Check if the object is a JS array or not. | 3560 // Check if the object is a JS array or not. |
| 3629 __ cmp(eax, JS_ARRAY_TYPE); | 3561 __ cmp(eax, JS_ARRAY_TYPE); |
| 3630 __ bind(&answer); | 3562 true_target()->Branch(equal); |
| 3631 cc_reg_ = equal; | 3563 false_target()->Jump(); |
| 3632 } | 3564 } |
| 3633 | 3565 |
| 3634 | 3566 |
| 3635 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 3567 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
| 3636 ASSERT(args->length() == 0); | 3568 ASSERT(args->length() == 0); |
| 3637 | 3569 |
| 3638 // Seed the result with the formal parameters count, which will be | 3570 // Seed the result with the formal parameters count, which will be |
| 3639 // used in case no arguments adaptor frame is found below the | 3571 // used in case no arguments adaptor frame is found below the |
| 3640 // current frame. | 3572 // current frame. |
| 3641 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3573 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3712 | 3644 |
| 3713 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 3645 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 3714 ASSERT(args->length() == 2); | 3646 ASSERT(args->length() == 2); |
| 3715 | 3647 |
| 3716 // Load the two objects into registers and perform the comparison. | 3648 // Load the two objects into registers and perform the comparison. |
| 3717 LoadAndSpill(args->at(0)); | 3649 LoadAndSpill(args->at(0)); |
| 3718 LoadAndSpill(args->at(1)); | 3650 LoadAndSpill(args->at(1)); |
| 3719 frame_->EmitPop(eax); | 3651 frame_->EmitPop(eax); |
| 3720 frame_->EmitPop(ecx); | 3652 frame_->EmitPop(ecx); |
| 3721 __ cmp(eax, Operand(ecx)); | 3653 __ cmp(eax, Operand(ecx)); |
| 3722 cc_reg_ = equal; | 3654 true_target()->Branch(equal); |
| 3655 false_target()->Jump(); |
| 3723 } | 3656 } |
| 3724 | 3657 |
| 3725 | 3658 |
| 3726 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 3659 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 3727 VirtualFrame::SpilledScope spilled_scope(this); | 3660 VirtualFrame::SpilledScope spilled_scope(this); |
| 3728 if (CheckForInlineRuntimeCall(node)) { | 3661 if (CheckForInlineRuntimeCall(node)) { |
| 3729 return; | 3662 return; |
| 3730 } | 3663 } |
| 3731 | 3664 |
| 3732 ZoneList<Expression*>* args = node->arguments(); | 3665 ZoneList<Expression*>* args = node->arguments(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3767 // expression to a literal string, this function can fail to leave a value | 3700 // expression to a literal string, this function can fail to leave a value |
| 3768 // on top of the frame or in the cc register. | 3701 // on top of the frame or in the cc register. |
| 3769 Comment cmnt(masm_, "[ UnaryOperation"); | 3702 Comment cmnt(masm_, "[ UnaryOperation"); |
| 3770 | 3703 |
| 3771 Token::Value op = node->op(); | 3704 Token::Value op = node->op(); |
| 3772 | 3705 |
| 3773 if (op == Token::NOT) { | 3706 if (op == Token::NOT) { |
| 3774 VirtualFrame::SpilledScope spilled_scope(this); | 3707 VirtualFrame::SpilledScope spilled_scope(this); |
| 3775 LoadConditionAndSpill(node->expression(), NOT_INSIDE_TYPEOF, | 3708 LoadConditionAndSpill(node->expression(), NOT_INSIDE_TYPEOF, |
| 3776 false_target(), true_target(), true); | 3709 false_target(), true_target(), true); |
| 3777 cc_reg_ = NegateCondition(cc_reg_); | |
| 3778 | 3710 |
| 3779 } else if (op == Token::DELETE) { | 3711 } else if (op == Token::DELETE) { |
| 3780 VirtualFrame::SpilledScope spilled_scope(this); | 3712 VirtualFrame::SpilledScope spilled_scope(this); |
| 3781 Property* property = node->expression()->AsProperty(); | 3713 Property* property = node->expression()->AsProperty(); |
| 3782 if (property != NULL) { | 3714 if (property != NULL) { |
| 3783 LoadAndSpill(property->obj()); | 3715 LoadAndSpill(property->obj()); |
| 3784 LoadAndSpill(property->key()); | 3716 LoadAndSpill(property->key()); |
| 3785 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3717 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3786 frame_->EmitPush(eax); | 3718 frame_->EmitPush(eax); |
| 3787 return; | 3719 return; |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4102 // the CC register), we force the right hand side to do the | 4034 // the CC register), we force the right hand side to do the |
| 4103 // same. This is necessary because we may have to branch to the exit | 4035 // same. This is necessary because we may have to branch to the exit |
| 4104 // after evaluating the left hand side (due to the shortcut | 4036 // after evaluating the left hand side (due to the shortcut |
| 4105 // semantics), but the compiler must (statically) know if the result | 4037 // semantics), but the compiler must (statically) know if the result |
| 4106 // of compiling the binary operation is materialized or not. | 4038 // of compiling the binary operation is materialized or not. |
| 4107 | 4039 |
| 4108 if (op == Token::AND) { | 4040 if (op == Token::AND) { |
| 4109 JumpTarget is_true(this); | 4041 JumpTarget is_true(this); |
| 4110 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, | 4042 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, |
| 4111 &is_true, false_target(), false); | 4043 &is_true, false_target(), false); |
| 4112 if (has_cc() || frame_ == NULL) { | 4044 if (!has_valid_frame()) { |
| 4113 if (has_cc()) { | |
| 4114 ASSERT(has_valid_frame()); | |
| 4115 Branch(false, false_target()); | |
| 4116 } | |
| 4117 | |
| 4118 if (is_true.is_linked()) { | 4045 if (is_true.is_linked()) { |
| 4046 // Evaluate right side expression. |
| 4119 is_true.Bind(); | 4047 is_true.Bind(); |
| 4120 } | |
| 4121 if (has_valid_frame()) { | |
| 4122 // Evaluate right side expression. | |
| 4123 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, | 4048 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, |
| 4124 true_target(), false_target(), false); | 4049 true_target(), false_target(), false); |
| 4125 } | 4050 } |
| 4126 } else { | 4051 } else { |
| 4127 // We have a materialized value on the frame. | 4052 // We have a materialized value on the frame. |
| 4128 JumpTarget pop_and_continue(this); | 4053 JumpTarget pop_and_continue(this); |
| 4129 JumpTarget exit(this); | 4054 JumpTarget exit(this); |
| 4130 | 4055 |
| 4131 // Avoid popping the result if it converts to 'false' using the | 4056 // Avoid popping the result if it converts to 'false' using the |
| 4132 // standard ToBoolean() conversion as described in ECMA-262, section | 4057 // standard ToBoolean() conversion as described in ECMA-262, section |
| 4133 // 9.2, page 30. | 4058 // 9.2, page 30. |
| 4134 // | 4059 // |
| 4135 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 4060 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 4136 frame_->Dup(); | 4061 frame_->Dup(); |
| 4137 ToBoolean(&pop_and_continue, &exit); | 4062 ToBoolean(&pop_and_continue, &exit); |
| 4138 Branch(false, &exit); | |
| 4139 | 4063 |
| 4140 // Pop the result of evaluating the first part. | 4064 // Pop the result of evaluating the first part. |
| 4141 pop_and_continue.Bind(); | 4065 pop_and_continue.Bind(); |
| 4142 frame_->Drop(); | 4066 frame_->Drop(); |
| 4143 | 4067 |
| 4144 // Evaluate right side expression. | 4068 // Evaluate right side expression. |
| 4145 is_true.Bind(); | 4069 is_true.Bind(); |
| 4146 Load(node->right()); | 4070 Load(node->right()); |
| 4147 | 4071 |
| 4148 // Exit (always with a materialized value). | 4072 // Exit (always with a materialized value). |
| 4149 exit.Bind(); | 4073 exit.Bind(); |
| 4150 } | 4074 } |
| 4151 | 4075 |
| 4152 } else if (op == Token::OR) { | 4076 } else if (op == Token::OR) { |
| 4153 JumpTarget is_false(this); | 4077 JumpTarget is_false(this); |
| 4154 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, | 4078 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, |
| 4155 true_target(), &is_false, false); | 4079 true_target(), &is_false, false); |
| 4156 if (has_cc() || frame_ == NULL) { | 4080 if (!has_valid_frame()) { |
| 4157 if (has_cc()) { | |
| 4158 ASSERT(has_valid_frame()); | |
| 4159 Branch(true, true_target()); | |
| 4160 } | |
| 4161 | |
| 4162 if (is_false.is_linked()) { | 4081 if (is_false.is_linked()) { |
| 4163 // Evaluate right side expression. | 4082 // Evaluate right side expression. |
| 4164 is_false.Bind(); | 4083 is_false.Bind(); |
| 4165 } | |
| 4166 if (has_valid_frame()) { | |
| 4167 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, | 4084 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, |
| 4168 true_target(), false_target(), false); | 4085 true_target(), false_target(), false); |
| 4169 } | 4086 } |
| 4170 } else { | 4087 } else { |
| 4171 // We have a materialized value on the frame. | 4088 // We have a materialized value on the frame. |
| 4172 JumpTarget pop_and_continue(this); | 4089 JumpTarget pop_and_continue(this); |
| 4173 JumpTarget exit(this); | 4090 JumpTarget exit(this); |
| 4174 | 4091 |
| 4175 // Avoid popping the result if it converts to 'true' using the | 4092 // Avoid popping the result if it converts to 'true' using the |
| 4176 // standard ToBoolean() conversion as described in ECMA-262, | 4093 // standard ToBoolean() conversion as described in ECMA-262, |
| 4177 // section 9.2, page 30. | 4094 // section 9.2, page 30. |
| 4178 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 4095 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 4179 frame_->Dup(); | 4096 frame_->Dup(); |
| 4180 ToBoolean(&exit, &pop_and_continue); | 4097 ToBoolean(&exit, &pop_and_continue); |
| 4181 Branch(true, &exit); | |
| 4182 | 4098 |
| 4183 // Pop the result of evaluating the first part. | 4099 // Pop the result of evaluating the first part. |
| 4184 pop_and_continue.Bind(); | 4100 pop_and_continue.Bind(); |
| 4185 frame_->Drop(); | 4101 frame_->Drop(); |
| 4186 | 4102 |
| 4187 // Evaluate right side expression. | 4103 // Evaluate right side expression. |
| 4188 is_false.Bind(); | 4104 is_false.Bind(); |
| 4189 Load(node->right()); | 4105 Load(node->right()); |
| 4190 | 4106 |
| 4191 // Exit (always with a materialized value). | 4107 // Exit (always with a materialized value). |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4279 __ test(eax, Immediate(kSmiTagMask)); | 4195 __ test(eax, Immediate(kSmiTagMask)); |
| 4280 false_target()->Branch(equal); | 4196 false_target()->Branch(equal); |
| 4281 | 4197 |
| 4282 // It can be an undetectable object. | 4198 // It can be an undetectable object. |
| 4283 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 4199 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4284 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); | 4200 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); |
| 4285 __ and_(eax, 1 << Map::kIsUndetectable); | 4201 __ and_(eax, 1 << Map::kIsUndetectable); |
| 4286 __ cmp(eax, 1 << Map::kIsUndetectable); | 4202 __ cmp(eax, 1 << Map::kIsUndetectable); |
| 4287 } | 4203 } |
| 4288 | 4204 |
| 4289 cc_reg_ = equal; | 4205 true_target()->Branch(equal); |
| 4206 false_target()->Jump(); |
| 4290 return; | 4207 return; |
| 4291 } | 4208 } |
| 4292 } | 4209 } |
| 4293 | 4210 |
| 4294 // To make typeof testing for natives implemented in JavaScript really | 4211 // To make typeof testing for natives implemented in JavaScript really |
| 4295 // efficient, we generate special code for expressions of the form: | 4212 // efficient, we generate special code for expressions of the form: |
| 4296 // 'typeof <expression> == <string>'. | 4213 // 'typeof <expression> == <string>'. |
| 4297 UnaryOperation* operation = left->AsUnaryOperation(); | 4214 UnaryOperation* operation = left->AsUnaryOperation(); |
| 4298 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 4215 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 4299 (operation != NULL && operation->op() == Token::TYPEOF) && | 4216 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 4300 (right->AsLiteral() != NULL && | 4217 (right->AsLiteral() != NULL && |
| 4301 right->AsLiteral()->handle()->IsString())) { | 4218 right->AsLiteral()->handle()->IsString())) { |
| 4302 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 4219 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 4303 | 4220 |
| 4304 VirtualFrame::SpilledScope spilled_scope(this); | 4221 VirtualFrame::SpilledScope spilled_scope(this); |
| 4305 // Load the operand and move it to register edx. | 4222 // Load the operand and move it to register edx. |
| 4306 LoadTypeofExpression(operation->expression()); | 4223 LoadTypeofExpression(operation->expression()); |
| 4307 frame_->EmitPop(edx); | 4224 frame_->EmitPop(edx); |
| 4308 | 4225 |
| 4309 if (check->Equals(Heap::number_symbol())) { | 4226 if (check->Equals(Heap::number_symbol())) { |
| 4310 __ test(edx, Immediate(kSmiTagMask)); | 4227 __ test(edx, Immediate(kSmiTagMask)); |
| 4311 true_target()->Branch(zero); | 4228 true_target()->Branch(zero); |
| 4312 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4229 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4313 __ cmp(edx, Factory::heap_number_map()); | 4230 __ cmp(edx, Factory::heap_number_map()); |
| 4314 cc_reg_ = equal; | 4231 true_target()->Branch(equal); |
| 4232 false_target()->Jump(); |
| 4315 | 4233 |
| 4316 } else if (check->Equals(Heap::string_symbol())) { | 4234 } else if (check->Equals(Heap::string_symbol())) { |
| 4317 __ test(edx, Immediate(kSmiTagMask)); | 4235 __ test(edx, Immediate(kSmiTagMask)); |
| 4318 false_target()->Branch(zero); | 4236 false_target()->Branch(zero); |
| 4319 | 4237 |
| 4320 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4238 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4321 | 4239 |
| 4322 // It can be an undetectable string object. | 4240 // It can be an undetectable string object. |
| 4323 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 4241 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4324 __ and_(ecx, 1 << Map::kIsUndetectable); | 4242 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 4325 __ cmp(ecx, 1 << Map::kIsUndetectable); | 4243 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 4326 false_target()->Branch(equal); | 4244 false_target()->Branch(equal); |
| 4327 | 4245 |
| 4328 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 4246 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 4329 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 4247 __ cmp(ecx, FIRST_NONSTRING_TYPE); |
| 4330 cc_reg_ = less; | 4248 true_target()->Branch(less); |
| 4249 false_target()->Jump(); |
| 4331 | 4250 |
| 4332 } else if (check->Equals(Heap::boolean_symbol())) { | 4251 } else if (check->Equals(Heap::boolean_symbol())) { |
| 4333 __ cmp(edx, Factory::true_value()); | 4252 __ cmp(edx, Factory::true_value()); |
| 4334 true_target()->Branch(equal); | 4253 true_target()->Branch(equal); |
| 4335 __ cmp(edx, Factory::false_value()); | 4254 __ cmp(edx, Factory::false_value()); |
| 4336 cc_reg_ = equal; | 4255 true_target()->Branch(equal); |
| 4256 false_target()->Jump(); |
| 4337 | 4257 |
| 4338 } else if (check->Equals(Heap::undefined_symbol())) { | 4258 } else if (check->Equals(Heap::undefined_symbol())) { |
| 4339 __ cmp(edx, Factory::undefined_value()); | 4259 __ cmp(edx, Factory::undefined_value()); |
| 4340 true_target()->Branch(equal); | 4260 true_target()->Branch(equal); |
| 4341 | 4261 |
| 4342 __ test(edx, Immediate(kSmiTagMask)); | 4262 __ test(edx, Immediate(kSmiTagMask)); |
| 4343 false_target()->Branch(zero); | 4263 false_target()->Branch(zero); |
| 4344 | 4264 |
| 4345 // It can be an undetectable object. | 4265 // It can be an undetectable object. |
| 4346 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4266 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4347 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 4267 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4348 __ and_(ecx, 1 << Map::kIsUndetectable); | 4268 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 4349 __ cmp(ecx, 1 << Map::kIsUndetectable); | 4269 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 4350 | 4270 true_target()->Branch(equal); |
| 4351 cc_reg_ = equal; | 4271 false_target()->Jump(); |
| 4352 | 4272 |
| 4353 } else if (check->Equals(Heap::function_symbol())) { | 4273 } else if (check->Equals(Heap::function_symbol())) { |
| 4354 __ test(edx, Immediate(kSmiTagMask)); | 4274 __ test(edx, Immediate(kSmiTagMask)); |
| 4355 false_target()->Branch(zero); | 4275 false_target()->Branch(zero); |
| 4356 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4276 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4357 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 4277 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 4358 __ cmp(edx, JS_FUNCTION_TYPE); | 4278 __ cmp(edx, JS_FUNCTION_TYPE); |
| 4359 cc_reg_ = equal; | 4279 true_target()->Branch(equal); |
| 4280 false_target()->Jump(); |
| 4360 | 4281 |
| 4361 } else if (check->Equals(Heap::object_symbol())) { | 4282 } else if (check->Equals(Heap::object_symbol())) { |
| 4362 __ test(edx, Immediate(kSmiTagMask)); | 4283 __ test(edx, Immediate(kSmiTagMask)); |
| 4363 false_target()->Branch(zero); | 4284 false_target()->Branch(zero); |
| 4364 | 4285 |
| 4365 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 4286 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4366 __ cmp(edx, Factory::null_value()); | 4287 __ cmp(edx, Factory::null_value()); |
| 4367 true_target()->Branch(equal); | 4288 true_target()->Branch(equal); |
| 4368 | 4289 |
| 4369 // It can be an undetectable object. | 4290 // It can be an undetectable object. |
| 4370 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); | 4291 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); |
| 4371 __ and_(edx, 1 << Map::kIsUndetectable); | 4292 __ and_(edx, 1 << Map::kIsUndetectable); |
| 4372 __ cmp(edx, 1 << Map::kIsUndetectable); | 4293 __ cmp(edx, 1 << Map::kIsUndetectable); |
| 4373 false_target()->Branch(equal); | 4294 false_target()->Branch(equal); |
| 4374 | 4295 |
| 4375 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 4296 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 4376 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 4297 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 4377 false_target()->Branch(less); | 4298 false_target()->Branch(less); |
| 4378 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 4299 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 4379 cc_reg_ = less_equal; | 4300 true_target()->Branch(less_equal); |
| 4301 false_target()->Jump(); |
| 4380 | 4302 |
| 4381 } else { | 4303 } else { |
| 4382 // Uncommon case: typeof testing against a string literal that is | 4304 // Uncommon case: typeof testing against a string literal that is |
| 4383 // never returned from the typeof operator. | 4305 // never returned from the typeof operator. |
| 4384 false_target()->Jump(); | 4306 false_target()->Jump(); |
| 4385 // TODO(kmilliken) : Can this cause a problem because it is an expression | |
| 4386 // that exits without a virtual frame in place? | |
| 4387 } | 4307 } |
| 4388 return; | 4308 return; |
| 4389 } | 4309 } |
| 4390 | 4310 |
| 4391 Condition cc = no_condition; | 4311 Condition cc = no_condition; |
| 4392 bool strict = false; | 4312 bool strict = false; |
| 4393 switch (op) { | 4313 switch (op) { |
| 4394 case Token::EQ_STRICT: | 4314 case Token::EQ_STRICT: |
| 4395 strict = true; | 4315 strict = true; |
| 4396 // Fall through | 4316 // Fall through |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4415 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); | 4335 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); |
| 4416 frame_->Push(eax); // push the result | 4336 frame_->Push(eax); // push the result |
| 4417 return; | 4337 return; |
| 4418 } | 4338 } |
| 4419 case Token::INSTANCEOF: { | 4339 case Token::INSTANCEOF: { |
| 4420 Load(left); | 4340 Load(left); |
| 4421 Load(right); | 4341 Load(right); |
| 4422 InstanceofStub stub; | 4342 InstanceofStub stub; |
| 4423 frame_->CallStub(&stub, 2); | 4343 frame_->CallStub(&stub, 2); |
| 4424 __ test(eax, Operand(eax)); | 4344 __ test(eax, Operand(eax)); |
| 4425 cc_reg_ = zero; | 4345 true_target()->Branch(zero); |
| 4346 false_target()->Jump(); |
| 4426 return; | 4347 return; |
| 4427 } | 4348 } |
| 4428 default: | 4349 default: |
| 4429 UNREACHABLE(); | 4350 UNREACHABLE(); |
| 4430 } | 4351 } |
| 4431 | 4352 |
| 4432 // Optimize for the case where (at least) one of the expressions | 4353 // Optimize for the case where (at least) one of the expressions |
| 4433 // is a literal small integer. | 4354 // is a literal small integer. |
| 4434 if (IsInlineSmi(left->AsLiteral())) { | 4355 if (IsInlineSmi(left->AsLiteral())) { |
| 4435 Load(right); | 4356 Load(right); |
| 4436 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict); | 4357 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict); |
| 4437 return; | 4358 } else if (IsInlineSmi(right->AsLiteral())) { |
| 4438 } | |
| 4439 if (IsInlineSmi(right->AsLiteral())) { | |
| 4440 Load(left); | 4359 Load(left); |
| 4441 SmiComparison(cc, right->AsLiteral()->handle(), strict); | 4360 SmiComparison(cc, right->AsLiteral()->handle(), strict); |
| 4442 return; | 4361 } else { |
| 4362 Load(left); |
| 4363 Load(right); |
| 4364 Comparison(cc, strict, true_target(), false_target()); |
| 4443 } | 4365 } |
| 4444 | |
| 4445 Load(left); | |
| 4446 Load(right); | |
| 4447 Comparison(cc, strict); | |
| 4448 } | 4366 } |
| 4449 | 4367 |
| 4450 | 4368 |
| 4451 #ifdef DEBUG | 4369 #ifdef DEBUG |
| 4452 bool CodeGenerator::HasValidEntryRegisters() { | 4370 bool CodeGenerator::HasValidEntryRegisters() { |
| 4453 return (allocator()->count(eax) == frame()->register_count(eax)) | 4371 return (allocator()->count(eax) == frame()->register_count(eax)) |
| 4454 && (allocator()->count(ebx) == frame()->register_count(ebx)) | 4372 && (allocator()->count(ebx) == frame()->register_count(ebx)) |
| 4455 && (allocator()->count(ecx) == frame()->register_count(ecx)) | 4373 && (allocator()->count(ecx) == frame()->register_count(ecx)) |
| 4456 && (allocator()->count(edx) == frame()->register_count(edx)) | 4374 && (allocator()->count(edx) == frame()->register_count(edx)) |
| 4457 && (allocator()->count(edi) == frame()->register_count(edi)); | 4375 && (allocator()->count(edi) == frame()->register_count(edi)); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4527 Literal* raw_name = property->key()->AsLiteral(); | 4445 Literal* raw_name = property->key()->AsLiteral(); |
| 4528 ASSERT(raw_name != NULL); | 4446 ASSERT(raw_name != NULL); |
| 4529 return Handle<String>(String::cast(*raw_name->handle())); | 4447 return Handle<String>(String::cast(*raw_name->handle())); |
| 4530 } | 4448 } |
| 4531 } | 4449 } |
| 4532 | 4450 |
| 4533 | 4451 |
| 4534 void Reference::GetValue(TypeofState typeof_state) { | 4452 void Reference::GetValue(TypeofState typeof_state) { |
| 4535 ASSERT(!cgen_->in_spilled_code()); | 4453 ASSERT(!cgen_->in_spilled_code()); |
| 4536 ASSERT(!is_illegal()); | 4454 ASSERT(!is_illegal()); |
| 4537 ASSERT(!cgen_->has_cc()); | |
| 4538 MacroAssembler* masm = cgen_->masm(); | 4455 MacroAssembler* masm = cgen_->masm(); |
| 4539 switch (type_) { | 4456 switch (type_) { |
| 4540 case SLOT: { | 4457 case SLOT: { |
| 4541 Comment cmnt(masm, "[ Load from Slot"); | 4458 Comment cmnt(masm, "[ Load from Slot"); |
| 4542 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4459 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 4543 ASSERT(slot != NULL); | 4460 ASSERT(slot != NULL); |
| 4544 cgen_->LoadFromSlot(slot, typeof_state); | 4461 cgen_->LoadFromSlot(slot, typeof_state); |
| 4545 break; | 4462 break; |
| 4546 } | 4463 } |
| 4547 | 4464 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4680 UNREACHABLE(); | 4597 UNREACHABLE(); |
| 4681 } | 4598 } |
| 4682 } | 4599 } |
| 4683 | 4600 |
| 4684 | 4601 |
| 4685 void Reference::TakeValue(TypeofState typeof_state) { | 4602 void Reference::TakeValue(TypeofState typeof_state) { |
| 4686 // For non-constant frame-allocated slots, we invalidate the value in the | 4603 // For non-constant frame-allocated slots, we invalidate the value in the |
| 4687 // slot. For all others, we fall back on GetValue. | 4604 // slot. For all others, we fall back on GetValue. |
| 4688 ASSERT(!cgen_->in_spilled_code()); | 4605 ASSERT(!cgen_->in_spilled_code()); |
| 4689 ASSERT(!is_illegal()); | 4606 ASSERT(!is_illegal()); |
| 4690 ASSERT(!cgen_->has_cc()); | |
| 4691 if (type_ != SLOT) { | 4607 if (type_ != SLOT) { |
| 4692 GetValue(typeof_state); | 4608 GetValue(typeof_state); |
| 4693 return; | 4609 return; |
| 4694 } | 4610 } |
| 4695 | 4611 |
| 4696 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4612 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 4697 ASSERT(slot != NULL); | 4613 ASSERT(slot != NULL); |
| 4698 if (slot->type() == Slot::LOOKUP || | 4614 if (slot->type() == Slot::LOOKUP || |
| 4699 slot->type() == Slot::CONTEXT || | 4615 slot->type() == Slot::CONTEXT || |
| 4700 slot->var()->mode() == Variable::CONST) { | 4616 slot->var()->mode() == Variable::CONST) { |
| 4701 GetValue(typeof_state); | 4617 GetValue(typeof_state); |
| 4702 return; | 4618 return; |
| 4703 } | 4619 } |
| 4704 | 4620 |
| 4705 // Only non-constant, frame-allocated parameters and locals can reach | 4621 // Only non-constant, frame-allocated parameters and locals can reach |
| 4706 // here. | 4622 // here. |
| 4707 if (slot->type() == Slot::PARAMETER) { | 4623 if (slot->type() == Slot::PARAMETER) { |
| 4708 cgen_->frame()->TakeParameterAt(slot->index()); | 4624 cgen_->frame()->TakeParameterAt(slot->index()); |
| 4709 } else { | 4625 } else { |
| 4710 ASSERT(slot->type() == Slot::LOCAL); | 4626 ASSERT(slot->type() == Slot::LOCAL); |
| 4711 cgen_->frame()->TakeLocalAt(slot->index()); | 4627 cgen_->frame()->TakeLocalAt(slot->index()); |
| 4712 } | 4628 } |
| 4713 } | 4629 } |
| 4714 | 4630 |
| 4715 | 4631 |
| 4716 void Reference::SetValue(InitState init_state) { | 4632 void Reference::SetValue(InitState init_state) { |
| 4717 ASSERT(!is_illegal()); | 4633 ASSERT(!is_illegal()); |
| 4718 ASSERT(!cgen_->has_cc()); | |
| 4719 MacroAssembler* masm = cgen_->masm(); | 4634 MacroAssembler* masm = cgen_->masm(); |
| 4720 VirtualFrame* frame = cgen_->frame(); | 4635 VirtualFrame* frame = cgen_->frame(); |
| 4721 switch (type_) { | 4636 switch (type_) { |
| 4722 case SLOT: { | 4637 case SLOT: { |
| 4723 Comment cmnt(masm, "[ Store to Slot"); | 4638 Comment cmnt(masm, "[ Store to Slot"); |
| 4724 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4639 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 4725 ASSERT(slot != NULL); | 4640 ASSERT(slot != NULL); |
| 4726 cgen_->StoreToSlot(slot, init_state); | 4641 cgen_->StoreToSlot(slot, init_state); |
| 4727 break; | 4642 break; |
| 4728 } | 4643 } |
| (...skipping 1514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6243 | 6158 |
| 6244 // Slow-case: Go through the JavaScript implementation. | 6159 // Slow-case: Go through the JavaScript implementation. |
| 6245 __ bind(&slow); | 6160 __ bind(&slow); |
| 6246 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6161 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6247 } | 6162 } |
| 6248 | 6163 |
| 6249 | 6164 |
| 6250 #undef __ | 6165 #undef __ |
| 6251 | 6166 |
| 6252 } } // namespace v8::internal | 6167 } } // namespace v8::internal |
| OLD | NEW |