OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 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 3405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3416 // ArgumentsAccessStub takes the parameter count as an input argument | 3416 // ArgumentsAccessStub takes the parameter count as an input argument |
3417 // in register eax. Create a constant result for it. | 3417 // in register eax. Create a constant result for it. |
3418 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters()))); | 3418 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters()))); |
3419 // Call the shared stub to get to the arguments.length. | 3419 // Call the shared stub to get to the arguments.length. |
3420 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 3420 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
3421 Result result = frame_->CallStub(&stub, &count); | 3421 Result result = frame_->CallStub(&stub, &count); |
3422 frame_->Push(&result); | 3422 frame_->Push(&result); |
3423 } | 3423 } |
3424 | 3424 |
3425 | 3425 |
3426 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* a) { | 3426 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
3427 // TODO(X64): Implement this function. | 3427 Comment(masm_, "[ GenerateFastCharCodeAt"); |
3428 // Ignore arguments and return undefined, to signal failure. | 3428 ASSERT(args->length() == 2); |
3429 frame_->Push(Factory::undefined_value()); | 3429 |
3430 Label slow_case; | |
3431 Label end; | |
3432 Label not_a_flat_string; | |
3433 Label a_cons_string; | |
3434 Label try_again_with_new_string; | |
3435 Label ascii_string; | |
3436 Label got_char_code; | |
3437 | |
3438 Load(args->at(0)); | |
3439 Load(args->at(1)); | |
3440 Result index = frame_->Pop(); | |
3441 Result object = frame_->Pop(); | |
3442 | |
3443 // Get register rcx to use as shift amount later. | |
3444 Result shift_amount; | |
3445 if (object.is_register() && object.reg().is(rcx)) { | |
3446 Result fresh = allocator_->Allocate(); | |
3447 shift_amount = object; | |
3448 object = fresh; | |
3449 __ movq(object.reg(), rcx); | |
3450 } | |
3451 if (index.is_register() && index.reg().is(rcx)) { | |
3452 Result fresh = allocator_->Allocate(); | |
3453 shift_amount = index; | |
3454 index = fresh; | |
3455 __ movq(index.reg(), rcx); | |
3456 } | |
3457 // There could be references to ecx in the frame. Allocating will | |
3458 // spill them, otherwise spill explicitly. | |
3459 if (shift_amount.is_valid()) { | |
3460 frame_->Spill(rcx); | |
3461 } else { | |
3462 shift_amount = allocator()->Allocate(rcx); | |
3463 } | |
3464 ASSERT(shift_amount.is_register()); | |
3465 ASSERT(shift_amount.reg().is(rcx)); | |
3466 ASSERT(allocator_->count(rcx) == 1); | |
3467 | |
3468 // We will mutate the index register and possibly the object register. | |
3469 // The case where they are somehow the same register is handled | |
3470 // because we only mutate them in the case where the receiver is a | |
3471 // heap object and the index is not. | |
3472 object.ToRegister(); | |
3473 index.ToRegister(); | |
3474 frame_->Spill(object.reg()); | |
3475 frame_->Spill(index.reg()); | |
3476 | |
3477 // We need a single extra temporary register. | |
3478 Result temp = allocator()->Allocate(); | |
3479 ASSERT(temp.is_valid()); | |
3480 | |
3481 // There is no virtual frame effect from here up to the final result | |
3482 // push. | |
3483 | |
3484 // If the receiver is a smi trigger the slow case. | |
3485 ASSERT(kSmiTag == 0); | |
3486 __ testl(object.reg(), Immediate(kSmiTagMask)); | |
3487 __ j(zero, &slow_case); | |
3488 | |
3489 // If the index is negative or non-smi trigger the slow case. | |
3490 ASSERT(kSmiTag == 0); | |
3491 __ testl(index.reg(), | |
3492 Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000U))); | |
William Hesse
2009/08/07 10:27:15
shouldn't this be a static cast to int32_t. I thi
Lasse Reichstein
2009/08/07 10:44:27
Done.
| |
3493 __ j(not_zero, &slow_case); | |
3494 // Untag the index. | |
3495 __ sarl(index.reg(), Immediate(kSmiTagSize)); | |
3496 | |
3497 __ bind(&try_again_with_new_string); | |
3498 // Fetch the instance type of the receiver into rcx. | |
3499 __ movq(rcx, FieldOperand(object.reg(), HeapObject::kMapOffset)); | |
3500 __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); | |
3501 // If the receiver is not a string trigger the slow case. | |
3502 __ testb(rcx, Immediate(kIsNotStringMask)); | |
3503 __ j(not_zero, &slow_case); | |
3504 | |
3505 // Here we make assumptions about the tag values and the shifts needed. | |
3506 // See the comment in objects.h. | |
3507 ASSERT(kLongStringTag == 0); | |
3508 ASSERT(kMediumStringTag + String::kLongLengthShift == | |
3509 String::kMediumLengthShift); | |
3510 ASSERT(kShortStringTag + String::kLongLengthShift == | |
3511 String::kShortLengthShift); | |
3512 __ and_(rcx, Immediate(kStringSizeMask)); | |
3513 __ addq(rcx, Immediate(String::kLongLengthShift)); | |
3514 // Fetch the length field into the temporary register. | |
3515 __ movl(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset)); | |
3516 __ shrl(temp.reg()); // The shift amount in ecx is implicit operand. | |
William Hesse
2009/08/07 10:27:15
cl (low byte of rcx), not ecx.
Is this a shr or sa
Lasse Reichstein
2009/08/07 10:44:27
Not sure whether high bit can be 1 (would be waste
| |
3517 // Check for index out of range. | |
3518 __ cmpl(index.reg(), temp.reg()); | |
3519 __ j(greater_equal, &slow_case); | |
William Hesse
2009/08/07 10:27:15
greater_equal or below_equal? Are either of these
Lasse Reichstein
2009/08/07 10:44:27
The string length is definitly positive, the index
| |
3520 // Reload the instance type (into the temp register this time).. | |
3521 __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); | |
3522 __ movzxbl(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); | |
3523 | |
3524 // We need special handling for non-flat strings. | |
3525 ASSERT(kSeqStringTag == 0); | |
3526 __ testb(temp.reg(), Immediate(kStringRepresentationMask)); | |
3527 __ j(not_zero, ¬_a_flat_string); | |
3528 // Check for 1-byte or 2-byte string. | |
3529 __ testb(temp.reg(), Immediate(kStringEncodingMask)); | |
3530 __ j(not_zero, &ascii_string); | |
3531 | |
3532 // 2-byte string. | |
3533 // Load the 2-byte character code into the temp register. | |
3534 __ movzxwl(temp.reg(), FieldOperand(object.reg(), | |
William Hesse
2009/08/07 10:27:15
Add the new operations to the disassembler.
Lasse Reichstein
2009/08/07 10:44:27
Already there. It's just a another operand size fo
Lasse Reichstein
2009/08/07 10:44:27
Already there. It's just a another operand size fo
| |
3535 index.reg(), | |
3536 times_2, | |
3537 SeqTwoByteString::kHeaderSize)); | |
3538 __ jmp(&got_char_code); | |
3539 | |
3540 // ASCII string. | |
3541 __ bind(&ascii_string); | |
3542 // Load the byte into the temp register. | |
3543 __ movzxbl(temp.reg(), FieldOperand(object.reg(), | |
3544 index.reg(), | |
3545 times_1, | |
3546 SeqAsciiString::kHeaderSize)); | |
3547 __ bind(&got_char_code); | |
3548 ASSERT(kSmiTag == 0); | |
3549 __ shl(temp.reg(), Immediate(kSmiTagSize)); | |
3550 __ jmp(&end); | |
3551 | |
3552 // Handle non-flat strings. | |
3553 __ bind(¬_a_flat_string); | |
3554 __ and_(temp.reg(), Immediate(kStringRepresentationMask)); | |
3555 __ cmpb(temp.reg(), Immediate(kConsStringTag)); | |
3556 __ j(equal, &a_cons_string); | |
3557 __ cmpb(temp.reg(), Immediate(kSlicedStringTag)); | |
3558 __ j(not_equal, &slow_case); | |
3559 | |
3560 // SlicedString. | |
3561 // Add the offset to the index and trigger the slow case on overflow. | |
3562 __ addl(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset)); | |
3563 __ j(overflow, &slow_case); | |
3564 // Getting the underlying string is done by running the cons string code. | |
3565 | |
3566 // ConsString. | |
3567 __ bind(&a_cons_string); | |
3568 // Get the first of the two strings. Both sliced and cons strings | |
3569 // store their source string at the same offset. | |
3570 ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset); | |
3571 __ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); | |
3572 __ jmp(&try_again_with_new_string); | |
3573 | |
3574 __ bind(&slow_case); | |
3575 // Move the undefined value into the result register, which will | |
3576 // trigger the slow case. | |
3577 __ Move(temp.reg(), Factory::undefined_value()); | |
3578 | |
3579 __ bind(&end); | |
3580 frame_->Push(&temp); | |
3430 } | 3581 } |
3431 | 3582 |
3432 | 3583 |
3433 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3584 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
3434 ASSERT(args->length() == 1); | 3585 ASSERT(args->length() == 1); |
3435 Load(args->at(0)); | 3586 Load(args->at(0)); |
3436 Result value = frame_->Pop(); | 3587 Result value = frame_->Pop(); |
3437 value.ToRegister(); | 3588 value.ToRegister(); |
3438 ASSERT(value.is_valid()); | 3589 ASSERT(value.is_valid()); |
3439 __ testl(value.reg(), | 3590 __ testl(value.reg(), |
(...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4145 __ Cmp(value.reg(), Factory::the_hole_value()); | 4296 __ Cmp(value.reg(), Factory::the_hole_value()); |
4146 frame_->Push(&value); | 4297 frame_->Push(&value); |
4147 exit.Branch(not_equal); | 4298 exit.Branch(not_equal); |
4148 Result arguments = StoreArgumentsObject(false); | 4299 Result arguments = StoreArgumentsObject(false); |
4149 frame_->SetElementAt(0, &arguments); | 4300 frame_->SetElementAt(0, &arguments); |
4150 exit.Bind(); | 4301 exit.Bind(); |
4151 } | 4302 } |
4152 | 4303 |
4153 | 4304 |
4154 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 4305 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
4155 // TODO(X64): Enable more types of slot. | |
4156 | |
4157 if (slot->type() == Slot::LOOKUP) { | 4306 if (slot->type() == Slot::LOOKUP) { |
4158 ASSERT(slot->var()->is_dynamic()); | 4307 ASSERT(slot->var()->is_dynamic()); |
4159 | 4308 |
4160 // For now, just do a runtime call. Since the call is inevitable, | 4309 // For now, just do a runtime call. Since the call is inevitable, |
4161 // we eagerly sync the virtual frame so we can directly push the | 4310 // we eagerly sync the virtual frame so we can directly push the |
4162 // arguments into place. | 4311 // arguments into place. |
4163 frame_->SyncRange(0, frame_->element_count() - 1); | 4312 frame_->SyncRange(0, frame_->element_count() - 1); |
4164 | 4313 |
4165 frame_->EmitPush(rsi); | 4314 frame_->EmitPush(rsi); |
4166 frame_->EmitPush(slot->var()->name()); | 4315 frame_->EmitPush(slot->var()->name()); |
(...skipping 3114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7281 int CompareStub::MinorKey() { | 7430 int CompareStub::MinorKey() { |
7282 // Encode the two parameters in a unique 16 bit value. | 7431 // Encode the two parameters in a unique 16 bit value. |
7283 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); | 7432 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); |
7284 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); | 7433 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
7285 } | 7434 } |
7286 | 7435 |
7287 | 7436 |
7288 #undef __ | 7437 #undef __ |
7289 | 7438 |
7290 } } // namespace v8::internal | 7439 } } // namespace v8::internal |
OLD | NEW |