| 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 |