OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 Isolate* isolate, | 343 Isolate* isolate, |
344 CodeStubInterfaceDescriptor* descriptor) { | 344 CodeStubInterfaceDescriptor* descriptor) { |
345 static Register registers[] = { rcx, rdx, rax }; | 345 static Register registers[] = { rcx, rdx, rax }; |
346 descriptor->register_param_count_ = 3; | 346 descriptor->register_param_count_ = 3; |
347 descriptor->register_params_ = registers; | 347 descriptor->register_params_ = registers; |
348 descriptor->deoptimization_handler_ = | 348 descriptor->deoptimization_handler_ = |
349 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); | 349 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); |
350 } | 350 } |
351 | 351 |
352 | 352 |
353 void NewStringAddStub::InitializeInterfaceDescriptor( | 353 void StringAddStub::InitializeInterfaceDescriptor( |
354 Isolate* isolate, | 354 Isolate* isolate, |
355 CodeStubInterfaceDescriptor* descriptor) { | 355 CodeStubInterfaceDescriptor* descriptor) { |
356 static Register registers[] = { rdx, rax }; | 356 static Register registers[] = { rdx, rax }; |
357 descriptor->register_param_count_ = 2; | 357 descriptor->register_param_count_ = 2; |
358 descriptor->register_params_ = registers; | 358 descriptor->register_params_ = registers; |
359 descriptor->deoptimization_handler_ = | 359 descriptor->deoptimization_handler_ = |
360 Runtime::FunctionForId(Runtime::kStringAdd)->entry; | 360 Runtime::FunctionForId(Runtime::kStringAdd)->entry; |
361 } | 361 } |
362 | 362 |
363 | 363 |
(...skipping 2873 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3237 if (!result_.is(rax)) { | 3237 if (!result_.is(rax)) { |
3238 __ movp(result_, rax); | 3238 __ movp(result_, rax); |
3239 } | 3239 } |
3240 call_helper.AfterCall(masm); | 3240 call_helper.AfterCall(masm); |
3241 __ jmp(&exit_); | 3241 __ jmp(&exit_); |
3242 | 3242 |
3243 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3243 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
3244 } | 3244 } |
3245 | 3245 |
3246 | 3246 |
3247 void StringAddStub::Generate(MacroAssembler* masm) { | |
3248 Label call_runtime, call_builtin; | |
3249 Builtins::JavaScript builtin_id = Builtins::ADD; | |
3250 | |
3251 // Load the two arguments. | |
3252 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); | |
3253 __ movp(rax, args.GetArgumentOperand(0)); // First argument (left). | |
3254 __ movp(rdx, args.GetArgumentOperand(1)); // Second argument (right). | |
3255 | |
3256 // Make sure that both arguments are strings if not known in advance. | |
3257 // Otherwise, at least one of the arguments is definitely a string, | |
3258 // and we convert the one that is not known to be a string. | |
3259 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { | |
3260 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); | |
3261 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); | |
3262 __ JumpIfSmi(rax, &call_runtime); | |
3263 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); | |
3264 __ j(above_equal, &call_runtime); | |
3265 | |
3266 // First argument is a a string, test second. | |
3267 __ JumpIfSmi(rdx, &call_runtime); | |
3268 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | |
3269 __ j(above_equal, &call_runtime); | |
3270 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { | |
3271 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); | |
3272 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, | |
3273 &call_builtin); | |
3274 builtin_id = Builtins::STRING_ADD_RIGHT; | |
3275 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { | |
3276 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); | |
3277 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, | |
3278 &call_builtin); | |
3279 builtin_id = Builtins::STRING_ADD_LEFT; | |
3280 } | |
3281 | |
3282 // Both arguments are strings. | |
3283 // rax: first string | |
3284 // rdx: second string | |
3285 // Check if either of the strings are empty. In that case return the other. | |
3286 Label second_not_zero_length, both_not_zero_length; | |
3287 __ movp(rcx, FieldOperand(rdx, String::kLengthOffset)); | |
3288 __ SmiTest(rcx); | |
3289 __ j(not_zero, &second_not_zero_length, Label::kNear); | |
3290 // Second string is empty, result is first string which is already in rax. | |
3291 Counters* counters = masm->isolate()->counters(); | |
3292 __ IncrementCounter(counters->string_add_native(), 1); | |
3293 __ ret(2 * kPointerSize); | |
3294 __ bind(&second_not_zero_length); | |
3295 __ movp(rbx, FieldOperand(rax, String::kLengthOffset)); | |
3296 __ SmiTest(rbx); | |
3297 __ j(not_zero, &both_not_zero_length, Label::kNear); | |
3298 // First string is empty, result is second string which is in rdx. | |
3299 __ movp(rax, rdx); | |
3300 __ IncrementCounter(counters->string_add_native(), 1); | |
3301 __ ret(2 * kPointerSize); | |
3302 | |
3303 // Both strings are non-empty. | |
3304 // rax: first string | |
3305 // rbx: length of first string | |
3306 // rcx: length of second string | |
3307 // rdx: second string | |
3308 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) | |
3309 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) | |
3310 Label string_add_flat_result, longer_than_two; | |
3311 __ bind(&both_not_zero_length); | |
3312 | |
3313 // If arguments where known to be strings, maps are not loaded to r8 and r9 | |
3314 // by the code above. | |
3315 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
3316 __ movp(r8, FieldOperand(rax, HeapObject::kMapOffset)); | |
3317 __ movp(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | |
3318 } | |
3319 // Get the instance types of the two strings as they will be needed soon. | |
3320 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | |
3321 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | |
3322 | |
3323 // Look at the length of the result of adding the two strings. | |
3324 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | |
3325 __ SmiAdd(rbx, rbx, rcx); | |
3326 // Use the string table when adding two one character strings, as it | |
3327 // helps later optimizations to return an internalized string here. | |
3328 __ SmiCompare(rbx, Smi::FromInt(2)); | |
3329 __ j(not_equal, &longer_than_two); | |
3330 | |
3331 // Check that both strings are non-external ASCII strings. | |
3332 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, | |
3333 &call_runtime); | |
3334 | |
3335 // Get the two characters forming the sub string. | |
3336 __ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | |
3337 __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); | |
3338 | |
3339 // Try to lookup two character string in string table. If it is not found | |
3340 // just allocate a new one. | |
3341 Label make_two_character_string, make_flat_ascii_string; | |
3342 StringHelper::GenerateTwoCharacterStringTableProbe( | |
3343 masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string); | |
3344 __ IncrementCounter(counters->string_add_native(), 1); | |
3345 __ ret(2 * kPointerSize); | |
3346 | |
3347 __ bind(&make_two_character_string); | |
3348 __ Set(rdi, 2); | |
3349 __ AllocateAsciiString(rax, rdi, r8, r9, r11, &call_runtime); | |
3350 // rbx - first byte: first character | |
3351 // rbx - second byte: *maybe* second character | |
3352 // Make sure that the second byte of rbx contains the second character. | |
3353 __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); | |
3354 __ shll(rcx, Immediate(kBitsPerByte)); | |
3355 __ orl(rbx, rcx); | |
3356 // Write both characters to the new string. | |
3357 __ movw(FieldOperand(rax, SeqOneByteString::kHeaderSize), rbx); | |
3358 __ IncrementCounter(counters->string_add_native(), 1); | |
3359 __ ret(2 * kPointerSize); | |
3360 | |
3361 __ bind(&longer_than_two); | |
3362 // Check if resulting string will be flat. | |
3363 __ SmiCompare(rbx, Smi::FromInt(ConsString::kMinLength)); | |
3364 __ j(below, &string_add_flat_result); | |
3365 // Handle exceptionally long strings in the runtime system. | |
3366 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | |
3367 __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength)); | |
3368 __ j(above, &call_runtime); | |
3369 | |
3370 // If result is not supposed to be flat, allocate a cons string object. If | |
3371 // both strings are ASCII the result is an ASCII cons string. | |
3372 // rax: first string | |
3373 // rbx: length of resulting flat string | |
3374 // rdx: second string | |
3375 // r8: instance type of first string | |
3376 // r9: instance type of second string | |
3377 Label non_ascii, allocated, ascii_data; | |
3378 __ movl(rcx, r8); | |
3379 __ and_(rcx, r9); | |
3380 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
3381 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
3382 __ testl(rcx, Immediate(kStringEncodingMask)); | |
3383 __ j(zero, &non_ascii); | |
3384 __ bind(&ascii_data); | |
3385 // Allocate an ASCII cons string. | |
3386 __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime); | |
3387 __ bind(&allocated); | |
3388 // Fill the fields of the cons string. | |
3389 __ movp(FieldOperand(rcx, ConsString::kLengthOffset), rbx); | |
3390 __ movp(FieldOperand(rcx, ConsString::kHashFieldOffset), | |
3391 Immediate(String::kEmptyHashField)); | |
3392 | |
3393 Label skip_write_barrier, after_writing; | |
3394 ExternalReference high_promotion_mode = ExternalReference:: | |
3395 new_space_high_promotion_mode_active_address(masm->isolate()); | |
3396 __ Load(rbx, high_promotion_mode); | |
3397 __ testb(rbx, Immediate(1)); | |
3398 __ j(zero, &skip_write_barrier); | |
3399 | |
3400 __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax); | |
3401 __ RecordWriteField(rcx, | |
3402 ConsString::kFirstOffset, | |
3403 rax, | |
3404 rbx, | |
3405 kDontSaveFPRegs); | |
3406 __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx); | |
3407 __ RecordWriteField(rcx, | |
3408 ConsString::kSecondOffset, | |
3409 rdx, | |
3410 rbx, | |
3411 kDontSaveFPRegs); | |
3412 __ jmp(&after_writing); | |
3413 | |
3414 __ bind(&skip_write_barrier); | |
3415 __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax); | |
3416 __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx); | |
3417 | |
3418 __ bind(&after_writing); | |
3419 | |
3420 __ movp(rax, rcx); | |
3421 __ IncrementCounter(counters->string_add_native(), 1); | |
3422 __ ret(2 * kPointerSize); | |
3423 __ bind(&non_ascii); | |
3424 // At least one of the strings is two-byte. Check whether it happens | |
3425 // to contain only one byte characters. | |
3426 // rcx: first instance type AND second instance type. | |
3427 // r8: first instance type. | |
3428 // r9: second instance type. | |
3429 __ testb(rcx, Immediate(kOneByteDataHintMask)); | |
3430 __ j(not_zero, &ascii_data); | |
3431 __ xor_(r8, r9); | |
3432 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); | |
3433 __ andb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); | |
3434 __ cmpb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); | |
3435 __ j(equal, &ascii_data); | |
3436 // Allocate a two byte cons string. | |
3437 __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime); | |
3438 __ jmp(&allocated); | |
3439 | |
3440 // We cannot encounter sliced strings or cons strings here since: | |
3441 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); | |
3442 // Handle creating a flat result from either external or sequential strings. | |
3443 // Locate the first characters' locations. | |
3444 // rax: first string | |
3445 // rbx: length of resulting flat string as smi | |
3446 // rdx: second string | |
3447 // r8: instance type of first string | |
3448 // r9: instance type of first string | |
3449 Label first_prepared, second_prepared; | |
3450 Label first_is_sequential, second_is_sequential; | |
3451 __ bind(&string_add_flat_result); | |
3452 | |
3453 __ SmiToInteger32(r14, FieldOperand(rax, SeqString::kLengthOffset)); | |
3454 // r14: length of first string | |
3455 STATIC_ASSERT(kSeqStringTag == 0); | |
3456 __ testb(r8, Immediate(kStringRepresentationMask)); | |
3457 __ j(zero, &first_is_sequential, Label::kNear); | |
3458 // Rule out short external string and load string resource. | |
3459 STATIC_ASSERT(kShortExternalStringTag != 0); | |
3460 __ testb(r8, Immediate(kShortExternalStringMask)); | |
3461 __ j(not_zero, &call_runtime); | |
3462 __ movp(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset)); | |
3463 __ jmp(&first_prepared, Label::kNear); | |
3464 __ bind(&first_is_sequential); | |
3465 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
3466 __ lea(rcx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | |
3467 __ bind(&first_prepared); | |
3468 | |
3469 // Check whether both strings have same encoding. | |
3470 __ xorl(r8, r9); | |
3471 __ testb(r8, Immediate(kStringEncodingMask)); | |
3472 __ j(not_zero, &call_runtime); | |
3473 | |
3474 __ SmiToInteger32(r15, FieldOperand(rdx, SeqString::kLengthOffset)); | |
3475 // r15: length of second string | |
3476 STATIC_ASSERT(kSeqStringTag == 0); | |
3477 __ testb(r9, Immediate(kStringRepresentationMask)); | |
3478 __ j(zero, &second_is_sequential, Label::kNear); | |
3479 // Rule out short external string and load string resource. | |
3480 STATIC_ASSERT(kShortExternalStringTag != 0); | |
3481 __ testb(r9, Immediate(kShortExternalStringMask)); | |
3482 __ j(not_zero, &call_runtime); | |
3483 __ movp(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset)); | |
3484 __ jmp(&second_prepared, Label::kNear); | |
3485 __ bind(&second_is_sequential); | |
3486 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
3487 __ lea(rdx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); | |
3488 __ bind(&second_prepared); | |
3489 | |
3490 Label non_ascii_string_add_flat_result; | |
3491 // r9: instance type of second string | |
3492 // First string and second string have the same encoding. | |
3493 STATIC_ASSERT(kTwoByteStringTag == 0); | |
3494 __ SmiToInteger32(rbx, rbx); | |
3495 __ testb(r9, Immediate(kStringEncodingMask)); | |
3496 __ j(zero, &non_ascii_string_add_flat_result); | |
3497 | |
3498 __ bind(&make_flat_ascii_string); | |
3499 // Both strings are ASCII strings. As they are short they are both flat. | |
3500 __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime); | |
3501 // rax: result string | |
3502 // Locate first character of result. | |
3503 __ lea(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | |
3504 // rcx: first char of first string | |
3505 // rbx: first character of result | |
3506 // r14: length of first string | |
3507 StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, true); | |
3508 // rbx: next character of result | |
3509 // rdx: first char of second string | |
3510 // r15: length of second string | |
3511 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, true); | |
3512 __ IncrementCounter(counters->string_add_native(), 1); | |
3513 __ ret(2 * kPointerSize); | |
3514 | |
3515 __ bind(&non_ascii_string_add_flat_result); | |
3516 // Both strings are ASCII strings. As they are short they are both flat. | |
3517 __ AllocateTwoByteString(rax, rbx, rdi, r8, r9, &call_runtime); | |
3518 // rax: result string | |
3519 // Locate first character of result. | |
3520 __ lea(rbx, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); | |
3521 // rcx: first char of first string | |
3522 // rbx: first character of result | |
3523 // r14: length of first string | |
3524 StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, false); | |
3525 // rbx: next character of result | |
3526 // rdx: first char of second string | |
3527 // r15: length of second string | |
3528 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); | |
3529 __ IncrementCounter(counters->string_add_native(), 1); | |
3530 __ ret(2 * kPointerSize); | |
3531 | |
3532 // Just jump to runtime to add the two strings. | |
3533 __ bind(&call_runtime); | |
3534 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | |
3535 | |
3536 if (call_builtin.is_linked()) { | |
3537 __ bind(&call_builtin); | |
3538 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | |
3539 } | |
3540 } | |
3541 | |
3542 | |
3543 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
3544 __ push(rax); | |
3545 __ push(rdx); | |
3546 } | |
3547 | |
3548 | |
3549 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm, | |
3550 Register temp) { | |
3551 __ PopReturnAddressTo(temp); | |
3552 __ pop(rdx); | |
3553 __ pop(rax); | |
3554 __ PushReturnAddressFrom(temp); | |
3555 } | |
3556 | |
3557 | |
3558 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | |
3559 int stack_offset, | |
3560 Register arg, | |
3561 Register scratch1, | |
3562 Register scratch2, | |
3563 Register scratch3, | |
3564 Label* slow) { | |
3565 // First check if the argument is already a string. | |
3566 Label not_string, done; | |
3567 __ JumpIfSmi(arg, ¬_string); | |
3568 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); | |
3569 __ j(below, &done); | |
3570 | |
3571 // Check the number to string cache. | |
3572 __ bind(¬_string); | |
3573 // Puts the cached result into scratch1. | |
3574 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow); | |
3575 __ movp(arg, scratch1); | |
3576 __ movp(Operand(rsp, stack_offset), arg); | |
3577 __ bind(&done); | |
3578 } | |
3579 | |
3580 | |
3581 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | |
3582 Register dest, | |
3583 Register src, | |
3584 Register count, | |
3585 bool ascii) { | |
3586 Label loop; | |
3587 __ bind(&loop); | |
3588 // This loop just copies one character at a time, as it is only used for very | |
3589 // short strings. | |
3590 if (ascii) { | |
3591 __ movb(kScratchRegister, Operand(src, 0)); | |
3592 __ movb(Operand(dest, 0), kScratchRegister); | |
3593 __ incq(src); | |
3594 __ incq(dest); | |
3595 } else { | |
3596 __ movzxwl(kScratchRegister, Operand(src, 0)); | |
3597 __ movw(Operand(dest, 0), kScratchRegister); | |
3598 __ addq(src, Immediate(2)); | |
3599 __ addq(dest, Immediate(2)); | |
3600 } | |
3601 __ decl(count); | |
3602 __ j(not_zero, &loop); | |
3603 } | |
3604 | |
3605 | |
3606 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, | 3247 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
3607 Register dest, | 3248 Register dest, |
3608 Register src, | 3249 Register src, |
3609 Register count, | 3250 Register count, |
3610 bool ascii) { | 3251 bool ascii) { |
3611 // Copy characters using rep movs of doublewords. Align destination on 4 byte | 3252 // Copy characters using rep movs of doublewords. Align destination on 4 byte |
3612 // boundary before starting rep movs. Copy remaining characters after running | 3253 // boundary before starting rep movs. Copy remaining characters after running |
3613 // rep movs. | 3254 // rep movs. |
3614 // Count is positive int32, dest and src are character pointers. | 3255 // Count is positive int32, dest and src are character pointers. |
3615 ASSERT(dest.is(rdi)); // rep movs destination | 3256 ASSERT(dest.is(rdi)); // rep movs destination |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3652 __ movb(kScratchRegister, Operand(src, 0)); | 3293 __ movb(kScratchRegister, Operand(src, 0)); |
3653 __ movb(Operand(dest, 0), kScratchRegister); | 3294 __ movb(Operand(dest, 0), kScratchRegister); |
3654 __ incq(src); | 3295 __ incq(src); |
3655 __ incq(dest); | 3296 __ incq(dest); |
3656 __ decl(count); | 3297 __ decl(count); |
3657 __ j(not_zero, &loop); | 3298 __ j(not_zero, &loop); |
3658 | 3299 |
3659 __ bind(&done); | 3300 __ bind(&done); |
3660 } | 3301 } |
3661 | 3302 |
3662 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, | |
3663 Register c1, | |
3664 Register c2, | |
3665 Register scratch1, | |
3666 Register scratch2, | |
3667 Register scratch3, | |
3668 Register scratch4, | |
3669 Label* not_found) { | |
3670 // Register scratch3 is the general scratch register in this function. | |
3671 Register scratch = scratch3; | |
3672 | |
3673 // Make sure that both characters are not digits as such strings has a | |
3674 // different hash algorithm. Don't try to look for these in the string table. | |
3675 Label not_array_index; | |
3676 __ leal(scratch, Operand(c1, -'0')); | |
3677 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | |
3678 __ j(above, ¬_array_index, Label::kNear); | |
3679 __ leal(scratch, Operand(c2, -'0')); | |
3680 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | |
3681 __ j(below_equal, not_found); | |
3682 | |
3683 __ bind(¬_array_index); | |
3684 // Calculate the two character string hash. | |
3685 Register hash = scratch1; | |
3686 GenerateHashInit(masm, hash, c1, scratch); | |
3687 GenerateHashAddCharacter(masm, hash, c2, scratch); | |
3688 GenerateHashGetHash(masm, hash, scratch); | |
3689 | |
3690 // Collect the two characters in a register. | |
3691 Register chars = c1; | |
3692 __ shl(c2, Immediate(kBitsPerByte)); | |
3693 __ orl(chars, c2); | |
3694 | |
3695 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
3696 // hash: hash of two character string. | |
3697 | |
3698 // Load the string table. | |
3699 Register string_table = c2; | |
3700 __ LoadRoot(string_table, Heap::kStringTableRootIndex); | |
3701 | |
3702 // Calculate capacity mask from the string table capacity. | |
3703 Register mask = scratch2; | |
3704 __ SmiToInteger32(mask, | |
3705 FieldOperand(string_table, StringTable::kCapacityOffset)); | |
3706 __ decl(mask); | |
3707 | |
3708 Register map = scratch4; | |
3709 | |
3710 // Registers | |
3711 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
3712 // hash: hash of two character string (32-bit int) | |
3713 // string_table: string table | |
3714 // mask: capacity mask (32-bit int) | |
3715 // map: - | |
3716 // scratch: - | |
3717 | |
3718 // Perform a number of probes in the string table. | |
3719 static const int kProbes = 4; | |
3720 Label found_in_string_table; | |
3721 Label next_probe[kProbes]; | |
3722 Register candidate = scratch; // Scratch register contains candidate. | |
3723 for (int i = 0; i < kProbes; i++) { | |
3724 // Calculate entry in string table. | |
3725 __ movl(scratch, hash); | |
3726 if (i > 0) { | |
3727 __ addl(scratch, Immediate(StringTable::GetProbeOffset(i))); | |
3728 } | |
3729 __ andl(scratch, mask); | |
3730 | |
3731 // Load the entry from the string table. | |
3732 STATIC_ASSERT(StringTable::kEntrySize == 1); | |
3733 __ movp(candidate, | |
3734 FieldOperand(string_table, | |
3735 scratch, | |
3736 times_pointer_size, | |
3737 StringTable::kElementsStartOffset)); | |
3738 | |
3739 // If entry is undefined no string with this hash can be found. | |
3740 Label is_string; | |
3741 __ CmpObjectType(candidate, ODDBALL_TYPE, map); | |
3742 __ j(not_equal, &is_string, Label::kNear); | |
3743 | |
3744 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); | |
3745 __ j(equal, not_found); | |
3746 // Must be the hole (deleted entry). | |
3747 if (FLAG_debug_code) { | |
3748 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | |
3749 __ cmpq(kScratchRegister, candidate); | |
3750 __ Assert(equal, kOddballInStringTableIsNotUndefinedOrTheHole); | |
3751 } | |
3752 __ jmp(&next_probe[i]); | |
3753 | |
3754 __ bind(&is_string); | |
3755 | |
3756 // If length is not 2 the string is not a candidate. | |
3757 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), | |
3758 Smi::FromInt(2)); | |
3759 __ j(not_equal, &next_probe[i]); | |
3760 | |
3761 // We use kScratchRegister as a temporary register in assumption that | |
3762 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly | |
3763 Register temp = kScratchRegister; | |
3764 | |
3765 // Check that the candidate is a non-external ASCII string. | |
3766 __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset)); | |
3767 __ JumpIfInstanceTypeIsNotSequentialAscii( | |
3768 temp, temp, &next_probe[i]); | |
3769 | |
3770 // Check if the two characters match. | |
3771 __ movl(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); | |
3772 __ andl(temp, Immediate(0x0000ffff)); | |
3773 __ cmpl(chars, temp); | |
3774 __ j(equal, &found_in_string_table); | |
3775 __ bind(&next_probe[i]); | |
3776 } | |
3777 | |
3778 // No matching 2 character string found by probing. | |
3779 __ jmp(not_found); | |
3780 | |
3781 // Scratch register contains result when we fall through to here. | |
3782 Register result = candidate; | |
3783 __ bind(&found_in_string_table); | |
3784 if (!result.is(rax)) { | |
3785 __ movp(rax, result); | |
3786 } | |
3787 } | |
3788 | |
3789 | 3303 |
3790 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 3304 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
3791 Register hash, | 3305 Register hash, |
3792 Register character, | 3306 Register character, |
3793 Register scratch) { | 3307 Register scratch) { |
3794 // hash = (seed + character) + ((seed + character) << 10); | 3308 // hash = (seed + character) + ((seed + character) << 10); |
3795 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); | 3309 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); |
3796 __ SmiToInteger32(scratch, scratch); | 3310 __ SmiToInteger32(scratch, scratch); |
3797 __ addl(scratch, character); | 3311 __ addl(scratch, character); |
3798 __ movl(hash, scratch); | 3312 __ movl(hash, scratch); |
(...skipping 1925 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5724 __ bind(&fast_elements_case); | 5238 __ bind(&fast_elements_case); |
5725 GenerateCase(masm, FAST_ELEMENTS); | 5239 GenerateCase(masm, FAST_ELEMENTS); |
5726 } | 5240 } |
5727 | 5241 |
5728 | 5242 |
5729 #undef __ | 5243 #undef __ |
5730 | 5244 |
5731 } } // namespace v8::internal | 5245 } } // namespace v8::internal |
5732 | 5246 |
5733 #endif // V8_TARGET_ARCH_X64 | 5247 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |