OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 Isolate* isolate, | 346 Isolate* isolate, |
347 CodeStubInterfaceDescriptor* descriptor) { | 347 CodeStubInterfaceDescriptor* descriptor) { |
348 static Register registers[] = { ecx, edx, eax }; | 348 static Register registers[] = { ecx, edx, eax }; |
349 descriptor->register_param_count_ = 3; | 349 descriptor->register_param_count_ = 3; |
350 descriptor->register_params_ = registers; | 350 descriptor->register_params_ = registers; |
351 descriptor->deoptimization_handler_ = | 351 descriptor->deoptimization_handler_ = |
352 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); | 352 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); |
353 } | 353 } |
354 | 354 |
355 | 355 |
356 void NewStringAddStub::InitializeInterfaceDescriptor( | 356 void StringAddStub::InitializeInterfaceDescriptor( |
357 Isolate* isolate, | 357 Isolate* isolate, |
358 CodeStubInterfaceDescriptor* descriptor) { | 358 CodeStubInterfaceDescriptor* descriptor) { |
359 static Register registers[] = { edx, eax }; | 359 static Register registers[] = { edx, eax }; |
360 descriptor->register_param_count_ = 2; | 360 descriptor->register_param_count_ = 2; |
361 descriptor->register_params_ = registers; | 361 descriptor->register_params_ = registers; |
362 descriptor->deoptimization_handler_ = | 362 descriptor->deoptimization_handler_ = |
363 Runtime::FunctionForId(Runtime::kStringAdd)->entry; | 363 Runtime::FunctionForId(Runtime::kStringAdd)->entry; |
364 } | 364 } |
365 | 365 |
366 | 366 |
(...skipping 3003 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3370 if (!result_.is(eax)) { | 3370 if (!result_.is(eax)) { |
3371 __ mov(result_, eax); | 3371 __ mov(result_, eax); |
3372 } | 3372 } |
3373 call_helper.AfterCall(masm); | 3373 call_helper.AfterCall(masm); |
3374 __ jmp(&exit_); | 3374 __ jmp(&exit_); |
3375 | 3375 |
3376 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3376 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
3377 } | 3377 } |
3378 | 3378 |
3379 | 3379 |
3380 void StringAddStub::Generate(MacroAssembler* masm) { | |
3381 Label call_runtime, call_builtin; | |
3382 Builtins::JavaScript builtin_id = Builtins::ADD; | |
3383 | |
3384 // Load the two arguments. | |
3385 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | |
3386 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | |
3387 | |
3388 // Make sure that both arguments are strings if not known in advance. | |
3389 // Otherwise, at least one of the arguments is definitely a string, | |
3390 // and we convert the one that is not known to be a string. | |
3391 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { | |
3392 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); | |
3393 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); | |
3394 __ JumpIfSmi(eax, &call_runtime); | |
3395 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); | |
3396 __ j(above_equal, &call_runtime); | |
3397 | |
3398 // First argument is a a string, test second. | |
3399 __ JumpIfSmi(edx, &call_runtime); | |
3400 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); | |
3401 __ j(above_equal, &call_runtime); | |
3402 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { | |
3403 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); | |
3404 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, | |
3405 &call_builtin); | |
3406 builtin_id = Builtins::STRING_ADD_RIGHT; | |
3407 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { | |
3408 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); | |
3409 GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi, | |
3410 &call_builtin); | |
3411 builtin_id = Builtins::STRING_ADD_LEFT; | |
3412 } | |
3413 | |
3414 // Both arguments are strings. | |
3415 // eax: first string | |
3416 // edx: second string | |
3417 // Check if either of the strings are empty. In that case return the other. | |
3418 Label second_not_zero_length, both_not_zero_length; | |
3419 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | |
3420 STATIC_ASSERT(kSmiTag == 0); | |
3421 __ test(ecx, ecx); | |
3422 __ j(not_zero, &second_not_zero_length, Label::kNear); | |
3423 // Second string is empty, result is first string which is already in eax. | |
3424 Counters* counters = masm->isolate()->counters(); | |
3425 __ IncrementCounter(counters->string_add_native(), 1); | |
3426 __ ret(2 * kPointerSize); | |
3427 __ bind(&second_not_zero_length); | |
3428 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | |
3429 STATIC_ASSERT(kSmiTag == 0); | |
3430 __ test(ebx, ebx); | |
3431 __ j(not_zero, &both_not_zero_length, Label::kNear); | |
3432 // First string is empty, result is second string which is in edx. | |
3433 __ mov(eax, edx); | |
3434 __ IncrementCounter(counters->string_add_native(), 1); | |
3435 __ ret(2 * kPointerSize); | |
3436 | |
3437 // Both strings are non-empty. | |
3438 // eax: first string | |
3439 // ebx: length of first string as a smi | |
3440 // ecx: length of second string as a smi | |
3441 // edx: second string | |
3442 // Look at the length of the result of adding the two strings. | |
3443 Label string_add_flat_result, longer_than_two; | |
3444 __ bind(&both_not_zero_length); | |
3445 __ add(ebx, ecx); | |
3446 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); | |
3447 // Handle exceptionally long strings in the runtime system. | |
3448 __ j(overflow, &call_runtime); | |
3449 // Use the string table when adding two one character strings, as it | |
3450 // helps later optimizations to return an internalized string here. | |
3451 __ cmp(ebx, Immediate(Smi::FromInt(2))); | |
3452 __ j(not_equal, &longer_than_two); | |
3453 | |
3454 // Check that both strings are non-external ASCII strings. | |
3455 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); | |
3456 | |
3457 // Get the two characters forming the new string. | |
3458 __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); | |
3459 __ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize)); | |
3460 | |
3461 // Try to lookup two character string in string table. If it is not found | |
3462 // just allocate a new one. | |
3463 Label make_two_character_string, make_two_character_string_no_reload; | |
3464 StringHelper::GenerateTwoCharacterStringTableProbe( | |
3465 masm, ebx, ecx, eax, edx, edi, | |
3466 &make_two_character_string_no_reload, &make_two_character_string); | |
3467 __ IncrementCounter(counters->string_add_native(), 1); | |
3468 __ ret(2 * kPointerSize); | |
3469 | |
3470 // Allocate a two character string. | |
3471 __ bind(&make_two_character_string); | |
3472 // Reload the arguments. | |
3473 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | |
3474 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | |
3475 // Get the two characters forming the new string. | |
3476 __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); | |
3477 __ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize)); | |
3478 __ bind(&make_two_character_string_no_reload); | |
3479 __ IncrementCounter(counters->string_add_make_two_char(), 1); | |
3480 __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); | |
3481 // Pack both characters in ebx. | |
3482 __ shl(ecx, kBitsPerByte); | |
3483 __ or_(ebx, ecx); | |
3484 // Set the characters in the new string. | |
3485 __ mov_w(FieldOperand(eax, SeqOneByteString::kHeaderSize), ebx); | |
3486 __ IncrementCounter(counters->string_add_native(), 1); | |
3487 __ ret(2 * kPointerSize); | |
3488 | |
3489 __ bind(&longer_than_two); | |
3490 // Check if resulting string will be flat. | |
3491 __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength))); | |
3492 __ j(below, &string_add_flat_result); | |
3493 | |
3494 // If result is not supposed to be flat allocate a cons string object. If both | |
3495 // strings are ASCII the result is an ASCII cons string. | |
3496 Label non_ascii, allocated, ascii_data; | |
3497 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); | |
3498 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); | |
3499 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | |
3500 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | |
3501 __ and_(ecx, edi); | |
3502 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
3503 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
3504 __ test(ecx, Immediate(kStringEncodingMask)); | |
3505 __ j(zero, &non_ascii); | |
3506 __ bind(&ascii_data); | |
3507 // Allocate an ASCII cons string. | |
3508 __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); | |
3509 __ bind(&allocated); | |
3510 // Fill the fields of the cons string. | |
3511 __ AssertSmi(ebx); | |
3512 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | |
3513 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | |
3514 Immediate(String::kEmptyHashField)); | |
3515 | |
3516 Label skip_write_barrier, after_writing; | |
3517 ExternalReference high_promotion_mode = ExternalReference:: | |
3518 new_space_high_promotion_mode_active_address(masm->isolate()); | |
3519 __ test(Operand::StaticVariable(high_promotion_mode), Immediate(1)); | |
3520 __ j(zero, &skip_write_barrier); | |
3521 | |
3522 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | |
3523 __ RecordWriteField(ecx, | |
3524 ConsString::kFirstOffset, | |
3525 eax, | |
3526 ebx, | |
3527 kDontSaveFPRegs); | |
3528 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | |
3529 __ RecordWriteField(ecx, | |
3530 ConsString::kSecondOffset, | |
3531 edx, | |
3532 ebx, | |
3533 kDontSaveFPRegs); | |
3534 __ jmp(&after_writing); | |
3535 | |
3536 __ bind(&skip_write_barrier); | |
3537 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | |
3538 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | |
3539 | |
3540 __ bind(&after_writing); | |
3541 | |
3542 __ mov(eax, ecx); | |
3543 __ IncrementCounter(counters->string_add_native(), 1); | |
3544 __ ret(2 * kPointerSize); | |
3545 __ bind(&non_ascii); | |
3546 // At least one of the strings is two-byte. Check whether it happens | |
3547 // to contain only one byte characters. | |
3548 // ecx: first instance type AND second instance type. | |
3549 // edi: second instance type. | |
3550 __ test(ecx, Immediate(kOneByteDataHintMask)); | |
3551 __ j(not_zero, &ascii_data); | |
3552 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | |
3553 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
3554 __ xor_(edi, ecx); | |
3555 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); | |
3556 __ and_(edi, kOneByteStringTag | kOneByteDataHintTag); | |
3557 __ cmp(edi, kOneByteStringTag | kOneByteDataHintTag); | |
3558 __ j(equal, &ascii_data); | |
3559 // Allocate a two byte cons string. | |
3560 __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); | |
3561 __ jmp(&allocated); | |
3562 | |
3563 // We cannot encounter sliced strings or cons strings here since: | |
3564 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); | |
3565 // Handle creating a flat result from either external or sequential strings. | |
3566 // Locate the first characters' locations. | |
3567 // eax: first string | |
3568 // ebx: length of resulting flat string as a smi | |
3569 // edx: second string | |
3570 Label first_prepared, second_prepared; | |
3571 Label first_is_sequential, second_is_sequential; | |
3572 __ bind(&string_add_flat_result); | |
3573 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | |
3574 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
3575 // ecx: instance type of first string | |
3576 STATIC_ASSERT(kSeqStringTag == 0); | |
3577 __ test_b(ecx, kStringRepresentationMask); | |
3578 __ j(zero, &first_is_sequential, Label::kNear); | |
3579 // Rule out short external string and load string resource. | |
3580 STATIC_ASSERT(kShortExternalStringTag != 0); | |
3581 __ test_b(ecx, kShortExternalStringMask); | |
3582 __ j(not_zero, &call_runtime); | |
3583 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); | |
3584 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
3585 __ jmp(&first_prepared, Label::kNear); | |
3586 __ bind(&first_is_sequential); | |
3587 __ add(eax, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
3588 __ bind(&first_prepared); | |
3589 | |
3590 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | |
3591 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | |
3592 // Check whether both strings have same encoding. | |
3593 // edi: instance type of second string | |
3594 __ xor_(ecx, edi); | |
3595 __ test_b(ecx, kStringEncodingMask); | |
3596 __ j(not_zero, &call_runtime); | |
3597 STATIC_ASSERT(kSeqStringTag == 0); | |
3598 __ test_b(edi, kStringRepresentationMask); | |
3599 __ j(zero, &second_is_sequential, Label::kNear); | |
3600 // Rule out short external string and load string resource. | |
3601 STATIC_ASSERT(kShortExternalStringTag != 0); | |
3602 __ test_b(edi, kShortExternalStringMask); | |
3603 __ j(not_zero, &call_runtime); | |
3604 __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); | |
3605 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
3606 __ jmp(&second_prepared, Label::kNear); | |
3607 __ bind(&second_is_sequential); | |
3608 __ add(edx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
3609 __ bind(&second_prepared); | |
3610 | |
3611 // Push the addresses of both strings' first characters onto the stack. | |
3612 __ push(edx); | |
3613 __ push(eax); | |
3614 | |
3615 Label non_ascii_string_add_flat_result, call_runtime_drop_two; | |
3616 // edi: instance type of second string | |
3617 // First string and second string have the same encoding. | |
3618 STATIC_ASSERT(kTwoByteStringTag == 0); | |
3619 __ test_b(edi, kStringEncodingMask); | |
3620 __ j(zero, &non_ascii_string_add_flat_result); | |
3621 | |
3622 // Both strings are ASCII strings. | |
3623 // ebx: length of resulting flat string as a smi | |
3624 __ SmiUntag(ebx); | |
3625 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); | |
3626 // eax: result string | |
3627 __ mov(ecx, eax); | |
3628 // Locate first character of result. | |
3629 __ add(ecx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
3630 // Load first argument's length and first character location. Account for | |
3631 // values currently on the stack when fetching arguments from it. | |
3632 __ mov(edx, Operand(esp, 4 * kPointerSize)); | |
3633 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
3634 __ SmiUntag(edi); | |
3635 __ pop(edx); | |
3636 // eax: result string | |
3637 // ecx: first character of result | |
3638 // edx: first char of first argument | |
3639 // edi: length of first argument | |
3640 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | |
3641 // Load second argument's length and first character location. Account for | |
3642 // values currently on the stack when fetching arguments from it. | |
3643 __ mov(edx, Operand(esp, 2 * kPointerSize)); | |
3644 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
3645 __ SmiUntag(edi); | |
3646 __ pop(edx); | |
3647 // eax: result string | |
3648 // ecx: next character of result | |
3649 // edx: first char of second argument | |
3650 // edi: length of second argument | |
3651 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | |
3652 __ IncrementCounter(counters->string_add_native(), 1); | |
3653 __ ret(2 * kPointerSize); | |
3654 | |
3655 // Handle creating a flat two byte result. | |
3656 // eax: first string - known to be two byte | |
3657 // ebx: length of resulting flat string as a smi | |
3658 // edx: second string | |
3659 __ bind(&non_ascii_string_add_flat_result); | |
3660 // Both strings are two byte strings. | |
3661 __ SmiUntag(ebx); | |
3662 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); | |
3663 // eax: result string | |
3664 __ mov(ecx, eax); | |
3665 // Locate first character of result. | |
3666 __ add(ecx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
3667 // Load second argument's length and first character location. Account for | |
3668 // values currently on the stack when fetching arguments from it. | |
3669 __ mov(edx, Operand(esp, 4 * kPointerSize)); | |
3670 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
3671 __ SmiUntag(edi); | |
3672 __ pop(edx); | |
3673 // eax: result string | |
3674 // ecx: first character of result | |
3675 // edx: first char of first argument | |
3676 // edi: length of first argument | |
3677 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | |
3678 // Load second argument's length and first character location. Account for | |
3679 // values currently on the stack when fetching arguments from it. | |
3680 __ mov(edx, Operand(esp, 2 * kPointerSize)); | |
3681 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
3682 __ SmiUntag(edi); | |
3683 __ pop(edx); | |
3684 // eax: result string | |
3685 // ecx: next character of result | |
3686 // edx: first char of second argument | |
3687 // edi: length of second argument | |
3688 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | |
3689 __ IncrementCounter(counters->string_add_native(), 1); | |
3690 __ ret(2 * kPointerSize); | |
3691 | |
3692 // Recover stack pointer before jumping to runtime. | |
3693 __ bind(&call_runtime_drop_two); | |
3694 __ Drop(2); | |
3695 // Just jump to runtime to add the two strings. | |
3696 __ bind(&call_runtime); | |
3697 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | |
3698 | |
3699 if (call_builtin.is_linked()) { | |
3700 __ bind(&call_builtin); | |
3701 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | |
3702 } | |
3703 } | |
3704 | |
3705 | |
3706 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
3707 __ push(eax); | |
3708 __ push(edx); | |
3709 } | |
3710 | |
3711 | |
3712 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm, | |
3713 Register temp) { | |
3714 __ pop(temp); | |
3715 __ pop(edx); | |
3716 __ pop(eax); | |
3717 __ push(temp); | |
3718 } | |
3719 | |
3720 | |
3721 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | |
3722 int stack_offset, | |
3723 Register arg, | |
3724 Register scratch1, | |
3725 Register scratch2, | |
3726 Register scratch3, | |
3727 Label* slow) { | |
3728 // First check if the argument is already a string. | |
3729 Label not_string, done; | |
3730 __ JumpIfSmi(arg, ¬_string); | |
3731 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); | |
3732 __ j(below, &done); | |
3733 | |
3734 // Check the number to string cache. | |
3735 __ bind(¬_string); | |
3736 // Puts the cached result into scratch1. | |
3737 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow); | |
3738 __ mov(arg, scratch1); | |
3739 __ mov(Operand(esp, stack_offset), arg); | |
3740 __ bind(&done); | |
3741 } | |
3742 | |
3743 | |
3744 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | |
3745 Register dest, | |
3746 Register src, | |
3747 Register count, | |
3748 Register scratch, | |
3749 bool ascii) { | |
3750 Label loop; | |
3751 __ bind(&loop); | |
3752 // This loop just copies one character at a time, as it is only used for very | |
3753 // short strings. | |
3754 if (ascii) { | |
3755 __ mov_b(scratch, Operand(src, 0)); | |
3756 __ mov_b(Operand(dest, 0), scratch); | |
3757 __ add(src, Immediate(1)); | |
3758 __ add(dest, Immediate(1)); | |
3759 } else { | |
3760 __ mov_w(scratch, Operand(src, 0)); | |
3761 __ mov_w(Operand(dest, 0), scratch); | |
3762 __ add(src, Immediate(2)); | |
3763 __ add(dest, Immediate(2)); | |
3764 } | |
3765 __ sub(count, Immediate(1)); | |
3766 __ j(not_zero, &loop); | |
3767 } | |
3768 | |
3769 | |
3770 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, | 3380 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
3771 Register dest, | 3381 Register dest, |
3772 Register src, | 3382 Register src, |
3773 Register count, | 3383 Register count, |
3774 Register scratch, | 3384 Register scratch, |
3775 bool ascii) { | 3385 bool ascii) { |
3776 // Copy characters using rep movs of doublewords. | 3386 // Copy characters using rep movs of doublewords. |
3777 // The destination is aligned on a 4 byte boundary because we are | 3387 // The destination is aligned on a 4 byte boundary because we are |
3778 // copying to the beginning of a newly allocated string. | 3388 // copying to the beginning of a newly allocated string. |
3779 ASSERT(dest.is(edi)); // rep movs destination | 3389 ASSERT(dest.is(edi)); // rep movs destination |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3820 __ mov_b(Operand(dest, 0), scratch); | 3430 __ mov_b(Operand(dest, 0), scratch); |
3821 __ add(src, Immediate(1)); | 3431 __ add(src, Immediate(1)); |
3822 __ add(dest, Immediate(1)); | 3432 __ add(dest, Immediate(1)); |
3823 __ sub(count, Immediate(1)); | 3433 __ sub(count, Immediate(1)); |
3824 __ j(not_zero, &loop); | 3434 __ j(not_zero, &loop); |
3825 | 3435 |
3826 __ bind(&done); | 3436 __ bind(&done); |
3827 } | 3437 } |
3828 | 3438 |
3829 | 3439 |
3830 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, | |
3831 Register c1, | |
3832 Register c2, | |
3833 Register scratch1, | |
3834 Register scratch2, | |
3835 Register scratch3, | |
3836 Label* not_probed, | |
3837 Label* not_found) { | |
3838 // Register scratch3 is the general scratch register in this function. | |
3839 Register scratch = scratch3; | |
3840 | |
3841 // Make sure that both characters are not digits as such strings has a | |
3842 // different hash algorithm. Don't try to look for these in the string table. | |
3843 Label not_array_index; | |
3844 __ mov(scratch, c1); | |
3845 __ sub(scratch, Immediate(static_cast<int>('0'))); | |
3846 __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); | |
3847 __ j(above, ¬_array_index, Label::kNear); | |
3848 __ mov(scratch, c2); | |
3849 __ sub(scratch, Immediate(static_cast<int>('0'))); | |
3850 __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); | |
3851 __ j(below_equal, not_probed); | |
3852 | |
3853 __ bind(¬_array_index); | |
3854 // Calculate the two character string hash. | |
3855 Register hash = scratch1; | |
3856 GenerateHashInit(masm, hash, c1, scratch); | |
3857 GenerateHashAddCharacter(masm, hash, c2, scratch); | |
3858 GenerateHashGetHash(masm, hash, scratch); | |
3859 | |
3860 // Collect the two characters in a register. | |
3861 Register chars = c1; | |
3862 __ shl(c2, kBitsPerByte); | |
3863 __ or_(chars, c2); | |
3864 | |
3865 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
3866 // hash: hash of two character string. | |
3867 | |
3868 // Load the string table. | |
3869 Register string_table = c2; | |
3870 __ LoadRoot(string_table, Heap::kStringTableRootIndex); | |
3871 | |
3872 // Calculate capacity mask from the string table capacity. | |
3873 Register mask = scratch2; | |
3874 __ mov(mask, FieldOperand(string_table, StringTable::kCapacityOffset)); | |
3875 __ SmiUntag(mask); | |
3876 __ sub(mask, Immediate(1)); | |
3877 | |
3878 // Registers | |
3879 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
3880 // hash: hash of two character string | |
3881 // string_table: string table | |
3882 // mask: capacity mask | |
3883 // scratch: - | |
3884 | |
3885 // Perform a number of probes in the string table. | |
3886 static const int kProbes = 4; | |
3887 Label found_in_string_table; | |
3888 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; | |
3889 Register candidate = scratch; // Scratch register contains candidate. | |
3890 for (int i = 0; i < kProbes; i++) { | |
3891 // Calculate entry in string table. | |
3892 __ mov(scratch, hash); | |
3893 if (i > 0) { | |
3894 __ add(scratch, Immediate(StringTable::GetProbeOffset(i))); | |
3895 } | |
3896 __ and_(scratch, mask); | |
3897 | |
3898 // Load the entry from the string table. | |
3899 STATIC_ASSERT(StringTable::kEntrySize == 1); | |
3900 __ mov(candidate, | |
3901 FieldOperand(string_table, | |
3902 scratch, | |
3903 times_pointer_size, | |
3904 StringTable::kElementsStartOffset)); | |
3905 | |
3906 // If entry is undefined no string with this hash can be found. | |
3907 Factory* factory = masm->isolate()->factory(); | |
3908 __ cmp(candidate, factory->undefined_value()); | |
3909 __ j(equal, not_found); | |
3910 __ cmp(candidate, factory->the_hole_value()); | |
3911 __ j(equal, &next_probe[i]); | |
3912 | |
3913 // If length is not 2 the string is not a candidate. | |
3914 __ cmp(FieldOperand(candidate, String::kLengthOffset), | |
3915 Immediate(Smi::FromInt(2))); | |
3916 __ j(not_equal, &next_probe[i]); | |
3917 | |
3918 // As we are out of registers save the mask on the stack and use that | |
3919 // register as a temporary. | |
3920 __ push(mask); | |
3921 Register temp = mask; | |
3922 | |
3923 // Check that the candidate is a non-external ASCII string. | |
3924 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); | |
3925 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | |
3926 __ JumpIfInstanceTypeIsNotSequentialAscii( | |
3927 temp, temp, &next_probe_pop_mask[i]); | |
3928 | |
3929 // Check if the two characters match. | |
3930 __ mov(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); | |
3931 __ and_(temp, 0x0000ffff); | |
3932 __ cmp(chars, temp); | |
3933 __ j(equal, &found_in_string_table); | |
3934 __ bind(&next_probe_pop_mask[i]); | |
3935 __ pop(mask); | |
3936 __ bind(&next_probe[i]); | |
3937 } | |
3938 | |
3939 // No matching 2 character string found by probing. | |
3940 __ jmp(not_found); | |
3941 | |
3942 // Scratch register contains result when we fall through to here. | |
3943 Register result = candidate; | |
3944 __ bind(&found_in_string_table); | |
3945 __ pop(mask); // Pop saved mask from the stack. | |
3946 if (!result.is(eax)) { | |
3947 __ mov(eax, result); | |
3948 } | |
3949 } | |
3950 | |
3951 | |
3952 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 3440 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
3953 Register hash, | 3441 Register hash, |
3954 Register character, | 3442 Register character, |
3955 Register scratch) { | 3443 Register scratch) { |
3956 // hash = (seed + character) + ((seed + character) << 10); | 3444 // hash = (seed + character) + ((seed + character) << 10); |
3957 if (Serializer::enabled()) { | 3445 if (Serializer::enabled()) { |
3958 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); | 3446 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); |
3959 __ SmiUntag(scratch); | 3447 __ SmiUntag(scratch); |
3960 __ add(scratch, character); | 3448 __ add(scratch, character); |
3961 __ mov(hash, scratch); | 3449 __ mov(hash, scratch); |
(...skipping 1949 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5911 __ bind(&fast_elements_case); | 5399 __ bind(&fast_elements_case); |
5912 GenerateCase(masm, FAST_ELEMENTS); | 5400 GenerateCase(masm, FAST_ELEMENTS); |
5913 } | 5401 } |
5914 | 5402 |
5915 | 5403 |
5916 #undef __ | 5404 #undef __ |
5917 | 5405 |
5918 } } // namespace v8::internal | 5406 } } // namespace v8::internal |
5919 | 5407 |
5920 #endif // V8_TARGET_ARCH_IA32 | 5408 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |