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 |