| 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 2402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2413 ASSERT(!in_spilled_code()); | 2413 ASSERT(!in_spilled_code()); |
| 2414 Comment cmnt(masm_, "[ WithExitStatement"); | 2414 Comment cmnt(masm_, "[ WithExitStatement"); |
| 2415 CodeForStatementPosition(node); | 2415 CodeForStatementPosition(node); |
| 2416 // Pop context. | 2416 // Pop context. |
| 2417 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 2417 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
| 2418 // Update context local. | 2418 // Update context local. |
| 2419 frame_->SaveContextRegister(); | 2419 frame_->SaveContextRegister(); |
| 2420 } | 2420 } |
| 2421 | 2421 |
| 2422 | 2422 |
| 2423 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | |
| 2424 return kFastSwitchMaxOverheadFactor; | |
| 2425 } | |
| 2426 | |
| 2427 | |
| 2428 int CodeGenerator::FastCaseSwitchMinCaseCount() { | |
| 2429 return kFastSwitchMinCaseCount; | |
| 2430 } | |
| 2431 | |
| 2432 | |
| 2433 // Generate a computed jump to a switch case. | |
| 2434 void CodeGenerator::GenerateFastCaseSwitchJumpTable( | |
| 2435 SwitchStatement* node, | |
| 2436 int min_index, | |
| 2437 int range, | |
| 2438 Label* default_label, | |
| 2439 Vector<Label*> case_targets, | |
| 2440 Vector<Label> case_labels) { | |
| 2441 // Notice: Internal references, used by both the jmp instruction and | |
| 2442 // the table entries, need to be relocated if the buffer grows. This | |
| 2443 // prevents the forward use of Labels, since a displacement cannot | |
| 2444 // survive relocation, and it also cannot safely be distinguished | |
| 2445 // from a real address. Instead we put in zero-values as | |
| 2446 // placeholders, and fill in the addresses after the labels have been | |
| 2447 // bound. | |
| 2448 | |
| 2449 JumpTarget setup_default; | |
| 2450 JumpTarget is_smi; | |
| 2451 | |
| 2452 // A non-null default label pointer indicates a default case among | |
| 2453 // the case labels. Otherwise we use the break target as a | |
| 2454 // "default". | |
| 2455 JumpTarget* default_target = | |
| 2456 (default_label == NULL) ? node->break_target() : &setup_default; | |
| 2457 | |
| 2458 // Test whether input is a smi. | |
| 2459 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | |
| 2460 Result switch_value = frame_->Pop(); | |
| 2461 switch_value.ToRegister(); | |
| 2462 __ test(switch_value.reg(), Immediate(kSmiTagMask)); | |
| 2463 is_smi.Branch(equal, &switch_value, taken); | |
| 2464 | |
| 2465 // It's a heap object, not a smi or a failure. Check if it is a | |
| 2466 // heap number. | |
| 2467 Result temp = allocator()->Allocate(); | |
| 2468 ASSERT(temp.is_valid()); | |
| 2469 __ CmpObjectType(switch_value.reg(), HEAP_NUMBER_TYPE, temp.reg()); | |
| 2470 temp.Unuse(); | |
| 2471 default_target->Branch(not_equal); | |
| 2472 | |
| 2473 // The switch value is a heap number. Convert it to a smi. | |
| 2474 frame_->Push(&switch_value); | |
| 2475 Result smi_value = frame_->CallRuntime(Runtime::kNumberToSmi, 1); | |
| 2476 | |
| 2477 is_smi.Bind(&smi_value); | |
| 2478 smi_value.ToRegister(); | |
| 2479 // Convert the switch value to a 0-based table index. | |
| 2480 if (min_index != 0) { | |
| 2481 frame_->Spill(smi_value.reg()); | |
| 2482 __ sub(Operand(smi_value.reg()), Immediate(min_index << kSmiTagSize)); | |
| 2483 } | |
| 2484 // Go to the default case if the table index is negative or not a smi. | |
| 2485 __ test(smi_value.reg(), Immediate(0x80000000 | kSmiTagMask)); | |
| 2486 default_target->Branch(not_equal, not_taken); | |
| 2487 __ cmp(smi_value.reg(), range << kSmiTagSize); | |
| 2488 default_target->Branch(greater_equal, not_taken); | |
| 2489 | |
| 2490 // The expected frame at all the case labels is a version of the | |
| 2491 // current one (the bidirectional entry frame, which an arbitrary | |
| 2492 // frame of the correct height can be merged to). Keep a copy to | |
| 2493 // restore at the start of every label. Create a jump target and | |
| 2494 // bind it to set its entry frame properly. | |
| 2495 JumpTarget entry_target(JumpTarget::BIDIRECTIONAL); | |
| 2496 entry_target.Bind(&smi_value); | |
| 2497 VirtualFrame* start_frame = new VirtualFrame(frame_); | |
| 2498 | |
| 2499 // 0 is placeholder. | |
| 2500 // Jump to the address at table_address + 2 * smi_value.reg(). | |
| 2501 // The target of the jump is read from table_address + 4 * switch_value. | |
| 2502 // The Smi encoding of smi_value.reg() is 2 * switch_value. | |
| 2503 smi_value.ToRegister(); | |
| 2504 __ jmp(Operand(smi_value.reg(), smi_value.reg(), | |
| 2505 times_1, 0x0, RelocInfo::INTERNAL_REFERENCE)); | |
| 2506 smi_value.Unuse(); | |
| 2507 // Calculate address to overwrite later with actual address of table. | |
| 2508 int32_t jump_table_ref = masm_->pc_offset() - sizeof(int32_t); | |
| 2509 __ Align(4); | |
| 2510 Label table_start; | |
| 2511 __ bind(&table_start); | |
| 2512 __ WriteInternalReference(jump_table_ref, table_start); | |
| 2513 | |
| 2514 for (int i = 0; i < range; i++) { | |
| 2515 // These are the table entries. 0x0 is the placeholder for case address. | |
| 2516 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE); | |
| 2517 } | |
| 2518 | |
| 2519 GenerateFastCaseSwitchCases(node, case_labels, start_frame); | |
| 2520 | |
| 2521 // If there was a default case, we need to emit the code to match it. | |
| 2522 if (default_label != NULL) { | |
| 2523 if (has_valid_frame()) { | |
| 2524 node->break_target()->Jump(); | |
| 2525 } | |
| 2526 setup_default.Bind(); | |
| 2527 frame_->MergeTo(start_frame); | |
| 2528 __ jmp(default_label); | |
| 2529 DeleteFrame(); | |
| 2530 } | |
| 2531 if (node->break_target()->is_linked()) { | |
| 2532 node->break_target()->Bind(); | |
| 2533 } | |
| 2534 | |
| 2535 for (int i = 0, entry_pos = table_start.pos(); | |
| 2536 i < range; | |
| 2537 i++, entry_pos += sizeof(uint32_t)) { | |
| 2538 if (case_targets[i] == NULL) { | |
| 2539 __ WriteInternalReference(entry_pos, | |
| 2540 *node->break_target()->entry_label()); | |
| 2541 } else { | |
| 2542 __ WriteInternalReference(entry_pos, *case_targets[i]); | |
| 2543 } | |
| 2544 } | |
| 2545 } | |
| 2546 | |
| 2547 | |
| 2548 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 2423 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 2549 ASSERT(!in_spilled_code()); | 2424 ASSERT(!in_spilled_code()); |
| 2550 Comment cmnt(masm_, "[ SwitchStatement"); | 2425 Comment cmnt(masm_, "[ SwitchStatement"); |
| 2551 CodeForStatementPosition(node); | 2426 CodeForStatementPosition(node); |
| 2552 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 2427 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 2553 | 2428 |
| 2554 // Compile the switch value. | 2429 // Compile the switch value. |
| 2555 Load(node->tag()); | 2430 Load(node->tag()); |
| 2556 | 2431 |
| 2557 if (TryGenerateFastCaseSwitchStatement(node)) { | |
| 2558 return; | |
| 2559 } | |
| 2560 | |
| 2561 ZoneList<CaseClause*>* cases = node->cases(); | 2432 ZoneList<CaseClause*>* cases = node->cases(); |
| 2562 int length = cases->length(); | 2433 int length = cases->length(); |
| 2563 CaseClause* default_clause = NULL; | 2434 CaseClause* default_clause = NULL; |
| 2564 | 2435 |
| 2565 JumpTarget next_test; | 2436 JumpTarget next_test; |
| 2566 // Compile the case label expressions and comparisons. Exit early | 2437 // Compile the case label expressions and comparisons. Exit early |
| 2567 // if a comparison is unconditionally true. The target next_test is | 2438 // if a comparison is unconditionally true. The target next_test is |
| 2568 // bound before the loop in order to indicate control flow to the | 2439 // bound before the loop in order to indicate control flow to the |
| 2569 // first comparison. | 2440 // first comparison. |
| 2570 next_test.Bind(); | 2441 next_test.Bind(); |
| (...skipping 5040 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7611 | 7482 |
| 7612 // Slow-case: Go through the JavaScript implementation. | 7483 // Slow-case: Go through the JavaScript implementation. |
| 7613 __ bind(&slow); | 7484 __ bind(&slow); |
| 7614 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7485 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 7615 } | 7486 } |
| 7616 | 7487 |
| 7617 | 7488 |
| 7618 #undef __ | 7489 #undef __ |
| 7619 | 7490 |
| 7620 } } // namespace v8::internal | 7491 } } // namespace v8::internal |
| OLD | NEW |