OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 7231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7242 __ cmp(dest, Operand(limit)); | 7242 __ cmp(dest, Operand(limit)); |
7243 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); | 7243 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); |
7244 __ b(ge, &done); | 7244 __ b(ge, &done); |
7245 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); | 7245 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); |
7246 __ b(&byte_loop); | 7246 __ b(&byte_loop); |
7247 | 7247 |
7248 __ bind(&done); | 7248 __ bind(&done); |
7249 } | 7249 } |
7250 | 7250 |
7251 | 7251 |
| 7252 void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
| 7253 Register c1, |
| 7254 Register c2, |
| 7255 Register scratch1, |
| 7256 Register scratch2, |
| 7257 Register scratch3, |
| 7258 Register scratch4, |
| 7259 Register scratch5, |
| 7260 Label* not_found) { |
| 7261 // Register scratch3 is the general scratch register in this function. |
| 7262 Register scratch = scratch3; |
| 7263 |
| 7264 // Make sure that both characters are not digits as such strings has a |
| 7265 // different hash algorithm. Don't try to look for these in the symbol table. |
| 7266 Label not_array_index; |
| 7267 __ sub(scratch, c1, Operand(static_cast<int>('0'))); |
| 7268 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); |
| 7269 __ b(hi, ¬_array_index); |
| 7270 __ sub(scratch, c2, Operand(static_cast<int>('0'))); |
| 7271 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); |
| 7272 |
| 7273 // If check failed combine both characters into single halfword. |
| 7274 // This is required by the contract of the method: code at the |
| 7275 // not_found branch expects this combination in c1 register |
| 7276 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls); |
| 7277 __ b(ls, not_found); |
| 7278 |
| 7279 __ bind(¬_array_index); |
| 7280 // Calculate the two character string hash. |
| 7281 Register hash = scratch1; |
| 7282 GenerateHashInit(masm, hash, c1); |
| 7283 GenerateHashAddCharacter(masm, hash, c2); |
| 7284 GenerateHashGetHash(masm, hash); |
| 7285 |
| 7286 // Collect the two characters in a register. |
| 7287 Register chars = c1; |
| 7288 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte)); |
| 7289 |
| 7290 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 7291 // hash: hash of two character string. |
| 7292 |
| 7293 // Load symbol table |
| 7294 // Load address of first element of the symbol table. |
| 7295 Register symbol_table = c2; |
| 7296 __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); |
| 7297 |
| 7298 // Load undefined value |
| 7299 Register undefined = scratch4; |
| 7300 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); |
| 7301 |
| 7302 // Calculate capacity mask from the symbol table capacity. |
| 7303 Register mask = scratch2; |
| 7304 __ ldr(mask, FieldMemOperand(symbol_table, SymbolTable::kCapacityOffset)); |
| 7305 __ mov(mask, Operand(mask, ASR, 1)); |
| 7306 __ sub(mask, mask, Operand(1)); |
| 7307 |
| 7308 // Calculate untagged address of the first element of the symbol table. |
| 7309 Register first_symbol_table_element = symbol_table; |
| 7310 __ add(first_symbol_table_element, symbol_table, |
| 7311 Operand(SymbolTable::kElementsStartOffset - kHeapObjectTag)); |
| 7312 |
| 7313 // Registers |
| 7314 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 7315 // hash: hash of two character string |
| 7316 // mask: capacity mask |
| 7317 // first_symbol_table_element: address of the first element of |
| 7318 // the symbol table |
| 7319 // scratch: - |
| 7320 |
| 7321 // Perform a number of probes in the symbol table. |
| 7322 static const int kProbes = 4; |
| 7323 Label found_in_symbol_table; |
| 7324 Label next_probe[kProbes]; |
| 7325 for (int i = 0; i < kProbes; i++) { |
| 7326 Register candidate = scratch5; // Scratch register contains candidate. |
| 7327 |
| 7328 // Calculate entry in symbol table. |
| 7329 if (i > 0) { |
| 7330 __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i))); |
| 7331 } else { |
| 7332 __ mov(candidate, hash); |
| 7333 } |
| 7334 |
| 7335 __ and_(candidate, candidate, Operand(mask)); |
| 7336 |
| 7337 // Load the entry from the symble table. |
| 7338 ASSERT_EQ(1, SymbolTable::kEntrySize); |
| 7339 __ ldr(candidate, |
| 7340 MemOperand(first_symbol_table_element, |
| 7341 candidate, |
| 7342 LSL, |
| 7343 kPointerSizeLog2)); |
| 7344 |
| 7345 // If entry is undefined no string with this hash can be found. |
| 7346 __ cmp(candidate, undefined); |
| 7347 __ b(eq, not_found); |
| 7348 |
| 7349 // If length is not 2 the string is not a candidate. |
| 7350 __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset)); |
| 7351 __ cmp(scratch, Operand(2)); |
| 7352 __ b(ne, &next_probe[i]); |
| 7353 |
| 7354 // Check that the candidate is a non-external ascii string. |
| 7355 __ ldr(scratch, FieldMemOperand(candidate, HeapObject::kMapOffset)); |
| 7356 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 7357 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, |
| 7358 &next_probe[i]); |
| 7359 |
| 7360 // Check if the two characters match. |
| 7361 // Assumes that word load is little endian. |
| 7362 __ ldrh(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize)); |
| 7363 __ cmp(chars, scratch); |
| 7364 __ b(eq, &found_in_symbol_table); |
| 7365 __ bind(&next_probe[i]); |
| 7366 } |
| 7367 |
| 7368 // No matching 2 character string found by probing. |
| 7369 __ jmp(not_found); |
| 7370 |
| 7371 // Scratch register contains result when we fall through to here. |
| 7372 Register result = scratch; |
| 7373 __ bind(&found_in_symbol_table); |
| 7374 if (!result.is(r0)) { |
| 7375 __ mov(r0, result); |
| 7376 } |
| 7377 } |
| 7378 |
| 7379 |
| 7380 void StringStubBase::GenerateHashInit(MacroAssembler* masm, |
| 7381 Register hash, |
| 7382 Register character) { |
| 7383 // hash = character + (character << 10); |
| 7384 __ add(hash, character, Operand(character, LSL, 10)); |
| 7385 // hash ^= hash >> 6; |
| 7386 __ eor(hash, hash, Operand(hash, ASR, 6)); |
| 7387 } |
| 7388 |
| 7389 |
| 7390 void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, |
| 7391 Register hash, |
| 7392 Register character) { |
| 7393 // hash += character; |
| 7394 __ add(hash, hash, Operand(character)); |
| 7395 // hash += hash << 10; |
| 7396 __ add(hash, hash, Operand(hash, LSL, 10)); |
| 7397 // hash ^= hash >> 6; |
| 7398 __ eor(hash, hash, Operand(hash, ASR, 6)); |
| 7399 } |
| 7400 |
| 7401 |
| 7402 void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, |
| 7403 Register hash) { |
| 7404 // hash += hash << 3; |
| 7405 __ add(hash, hash, Operand(hash, LSL, 3)); |
| 7406 // hash ^= hash >> 11; |
| 7407 __ eor(hash, hash, Operand(hash, ASR, 11)); |
| 7408 // hash += hash << 15; |
| 7409 __ add(hash, hash, Operand(hash, LSL, 15), SetCC); |
| 7410 |
| 7411 // if (hash == 0) hash = 27; |
| 7412 __ mov(hash, Operand(27), LeaveCC, nz); |
| 7413 } |
| 7414 |
| 7415 |
7252 void SubStringStub::Generate(MacroAssembler* masm) { | 7416 void SubStringStub::Generate(MacroAssembler* masm) { |
7253 Label runtime; | 7417 Label runtime; |
7254 | 7418 |
7255 // Stack frame on entry. | 7419 // Stack frame on entry. |
7256 // lr: return address | 7420 // lr: return address |
7257 // sp[0]: to | 7421 // sp[0]: to |
7258 // sp[4]: from | 7422 // sp[4]: from |
7259 // sp[8]: string | 7423 // sp[8]: string |
7260 | 7424 |
7261 // This stub is called from the native-call %_SubString(...), so | 7425 // This stub is called from the native-call %_SubString(...), so |
(...skipping 15 matching lines...) Expand all Loading... |
7277 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 7441 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
7278 // I.e., arithmetic shift right by one un-smi-tags. | 7442 // I.e., arithmetic shift right by one un-smi-tags. |
7279 __ mov(r2, Operand(r7, ASR, 1), SetCC); | 7443 __ mov(r2, Operand(r7, ASR, 1), SetCC); |
7280 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc); | 7444 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc); |
7281 // If either r2 or r6 had the smi tag bit set, then carry is set now. | 7445 // If either r2 or r6 had the smi tag bit set, then carry is set now. |
7282 __ b(cs, &runtime); // Either "from" or "to" is not a smi. | 7446 __ b(cs, &runtime); // Either "from" or "to" is not a smi. |
7283 __ b(mi, &runtime); // From is negative. | 7447 __ b(mi, &runtime); // From is negative. |
7284 | 7448 |
7285 __ sub(r2, r2, Operand(r3), SetCC); | 7449 __ sub(r2, r2, Operand(r3), SetCC); |
7286 __ b(mi, &runtime); // Fail if from > to. | 7450 __ b(mi, &runtime); // Fail if from > to. |
7287 // Handle sub-strings of length 2 and less in the runtime system. | 7451 // Special handling of sub-strings of length 1 and 2. One character strings |
| 7452 // are handled in the runtime system (looked up in the single character |
| 7453 // cache). Two character strings are looked for in the symbol cache. |
7288 __ cmp(r2, Operand(2)); | 7454 __ cmp(r2, Operand(2)); |
7289 __ b(le, &runtime); | 7455 __ b(lt, &runtime); |
7290 | 7456 |
7291 // r2: length | 7457 // r2: length |
| 7458 // r3: from index (untaged smi) |
7292 // r6: from (smi) | 7459 // r6: from (smi) |
7293 // r7: to (smi) | 7460 // r7: to (smi) |
7294 | 7461 |
7295 // Make sure first argument is a sequential (or flat) string. | 7462 // Make sure first argument is a sequential (or flat) string. |
7296 __ ldr(r5, MemOperand(sp, kStringOffset)); | 7463 __ ldr(r5, MemOperand(sp, kStringOffset)); |
7297 ASSERT_EQ(0, kSmiTag); | 7464 ASSERT_EQ(0, kSmiTag); |
7298 __ tst(r5, Operand(kSmiTagMask)); | 7465 __ tst(r5, Operand(kSmiTagMask)); |
7299 __ b(eq, &runtime); | 7466 __ b(eq, &runtime); |
7300 Condition is_string = masm->IsObjectStringType(r5, r1); | 7467 Condition is_string = masm->IsObjectStringType(r5, r1); |
7301 __ b(NegateCondition(is_string), &runtime); | 7468 __ b(NegateCondition(is_string), &runtime); |
7302 | 7469 |
7303 // r1: instance type | 7470 // r1: instance type |
7304 // r2: length | 7471 // r2: length |
| 7472 // r3: from index (untaged smi) |
7305 // r5: string | 7473 // r5: string |
7306 // r6: from (smi) | 7474 // r6: from (smi) |
7307 // r7: to (smi) | 7475 // r7: to (smi) |
7308 Label seq_string; | 7476 Label seq_string; |
7309 __ and_(r4, r1, Operand(kStringRepresentationMask)); | 7477 __ and_(r4, r1, Operand(kStringRepresentationMask)); |
7310 ASSERT(kSeqStringTag < kConsStringTag); | 7478 ASSERT(kSeqStringTag < kConsStringTag); |
7311 ASSERT(kExternalStringTag > kConsStringTag); | 7479 ASSERT(kExternalStringTag > kConsStringTag); |
7312 __ cmp(r4, Operand(kConsStringTag)); | 7480 __ cmp(r4, Operand(kConsStringTag)); |
7313 __ b(gt, &runtime); // External strings go to runtime. | 7481 __ b(gt, &runtime); // External strings go to runtime. |
7314 __ b(lt, &seq_string); // Sequential strings are handled directly. | 7482 __ b(lt, &seq_string); // Sequential strings are handled directly. |
7315 | 7483 |
7316 // Cons string. Try to recurse (once) on the first substring. | 7484 // Cons string. Try to recurse (once) on the first substring. |
7317 // (This adds a little more generality than necessary to handle flattened | 7485 // (This adds a little more generality than necessary to handle flattened |
7318 // cons strings, but not much). | 7486 // cons strings, but not much). |
7319 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); | 7487 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); |
7320 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); | 7488 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); |
7321 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 7489 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
7322 __ tst(r1, Operand(kStringRepresentationMask)); | 7490 __ tst(r1, Operand(kStringRepresentationMask)); |
7323 ASSERT_EQ(0, kSeqStringTag); | 7491 ASSERT_EQ(0, kSeqStringTag); |
7324 __ b(ne, &runtime); // Cons and External strings go to runtime. | 7492 __ b(ne, &runtime); // Cons and External strings go to runtime. |
7325 | 7493 |
7326 // Definitly a sequential string. | 7494 // Definitly a sequential string. |
7327 __ bind(&seq_string); | 7495 __ bind(&seq_string); |
7328 | 7496 |
7329 // r1: instance type. | 7497 // r1: instance type. |
7330 // r2: length | 7498 // r2: length |
| 7499 // r3: from index (untaged smi) |
7331 // r5: string | 7500 // r5: string |
7332 // r6: from (smi) | 7501 // r6: from (smi) |
7333 // r7: to (smi) | 7502 // r7: to (smi) |
7334 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); | 7503 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); |
7335 __ cmp(r4, Operand(r7, ASR, 1)); | 7504 __ cmp(r4, Operand(r7, ASR, 1)); |
7336 __ b(lt, &runtime); // Fail if to > length. | 7505 __ b(lt, &runtime); // Fail if to > length. |
7337 | 7506 |
7338 // r1: instance type. | 7507 // r1: instance type. |
7339 // r2: result string length. | 7508 // r2: result string length. |
| 7509 // r3: from index (untaged smi) |
7340 // r5: string. | 7510 // r5: string. |
7341 // r6: from offset (smi) | 7511 // r6: from offset (smi) |
7342 // Check for flat ascii string. | 7512 // Check for flat ascii string. |
7343 Label non_ascii_flat; | 7513 Label non_ascii_flat; |
7344 __ tst(r1, Operand(kStringEncodingMask)); | 7514 __ tst(r1, Operand(kStringEncodingMask)); |
7345 ASSERT_EQ(0, kTwoByteStringTag); | 7515 ASSERT_EQ(0, kTwoByteStringTag); |
7346 __ b(eq, &non_ascii_flat); | 7516 __ b(eq, &non_ascii_flat); |
7347 | 7517 |
| 7518 Label result_longer_than_two; |
| 7519 __ cmp(r2, Operand(2)); |
| 7520 __ b(gt, &result_longer_than_two); |
| 7521 |
| 7522 // Sub string of length 2 requested. |
| 7523 // Get the two characters forming the sub string. |
| 7524 __ add(r5, r5, Operand(r3)); |
| 7525 __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); |
| 7526 __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1)); |
| 7527 |
| 7528 // Try to lookup two character string in symbol table. |
| 7529 Label make_two_character_string; |
| 7530 GenerateTwoCharacterSymbolTableProbe(masm, r3, r4, r1, r5, r6, r7, r9, |
| 7531 &make_two_character_string); |
| 7532 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 7533 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 7534 __ Ret(); |
| 7535 |
| 7536 // r2: result string length. |
| 7537 // r3: two characters combined into halfword in little endian byte order. |
| 7538 __ bind(&make_two_character_string); |
| 7539 __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); |
| 7540 __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 7541 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 7542 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 7543 __ Ret(); |
| 7544 |
| 7545 __ bind(&result_longer_than_two); |
| 7546 |
7348 // Allocate the result. | 7547 // Allocate the result. |
7349 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); | 7548 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); |
7350 | 7549 |
7351 // r0: result string. | 7550 // r0: result string. |
7352 // r2: result string length. | 7551 // r2: result string length. |
7353 // r5: string. | 7552 // r5: string. |
7354 // r6: from offset (smi) | 7553 // r6: from offset (smi) |
7355 // Locate first character of result. | 7554 // Locate first character of result. |
7356 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 7555 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
7357 // Locate 'from' character of string. | 7556 // Locate 'from' character of string. |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7546 } | 7745 } |
7547 | 7746 |
7548 // Both strings are non-empty. | 7747 // Both strings are non-empty. |
7549 // r0: first string | 7748 // r0: first string |
7550 // r1: second string | 7749 // r1: second string |
7551 // r2: length of first string | 7750 // r2: length of first string |
7552 // r3: length of second string | 7751 // r3: length of second string |
7553 // r4: first string instance type (if string_check_) | 7752 // r4: first string instance type (if string_check_) |
7554 // r5: second string instance type (if string_check_) | 7753 // r5: second string instance type (if string_check_) |
7555 // Look at the length of the result of adding the two strings. | 7754 // Look at the length of the result of adding the two strings. |
7556 Label string_add_flat_result; | 7755 Label string_add_flat_result, longer_than_two; |
7557 // Adding two lengths can't overflow. | 7756 // Adding two lengths can't overflow. |
7558 ASSERT(String::kMaxLength * 2 > String::kMaxLength); | 7757 ASSERT(String::kMaxLength * 2 > String::kMaxLength); |
7559 __ add(r6, r2, Operand(r3)); | 7758 __ add(r6, r2, Operand(r3)); |
7560 // Use the runtime system when adding two one character strings, as it | 7759 // Use the runtime system when adding two one character strings, as it |
7561 // contains optimizations for this specific case using the symbol table. | 7760 // contains optimizations for this specific case using the symbol table. |
7562 __ cmp(r6, Operand(2)); | 7761 __ cmp(r6, Operand(2)); |
7563 __ b(eq, &string_add_runtime); | 7762 __ b(ne, &longer_than_two); |
| 7763 |
| 7764 // Check that both strings are non-external ascii strings. |
| 7765 if (!string_check_) { |
| 7766 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 7767 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 7768 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 7769 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
| 7770 } |
| 7771 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, |
| 7772 &string_add_runtime); |
| 7773 |
| 7774 // Get the two characters forming the sub string. |
| 7775 __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 7776 __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); |
| 7777 |
| 7778 // Try to lookup two character string in symbol table. If it is not found |
| 7779 // just allocate a new one. |
| 7780 Label make_two_character_string; |
| 7781 GenerateTwoCharacterSymbolTableProbe(masm, r2, r3, r6, r7, r4, r5, r9, |
| 7782 &make_two_character_string); |
| 7783 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 7784 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 7785 __ Ret(); |
| 7786 |
| 7787 __ bind(&make_two_character_string); |
| 7788 // Resulting string has length 2 and first chars of two strings |
| 7789 // are combined into single halfword in r2 register. |
| 7790 // So we can fill resulting string without two loops by a single |
| 7791 // halfword store instruction (which assumes that processor is |
| 7792 // in a little endian mode) |
| 7793 __ mov(r6, Operand(2)); |
| 7794 __ AllocateAsciiString(r0, r6, r4, r5, r9, &string_add_runtime); |
| 7795 __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 7796 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 7797 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 7798 __ Ret(); |
| 7799 |
| 7800 __ bind(&longer_than_two); |
7564 // Check if resulting string will be flat. | 7801 // Check if resulting string will be flat. |
7565 __ cmp(r6, Operand(String::kMinNonFlatLength)); | 7802 __ cmp(r6, Operand(String::kMinNonFlatLength)); |
7566 __ b(lt, &string_add_flat_result); | 7803 __ b(lt, &string_add_flat_result); |
7567 // Handle exceptionally long strings in the runtime system. | 7804 // Handle exceptionally long strings in the runtime system. |
7568 ASSERT((String::kMaxLength & 0x80000000) == 0); | 7805 ASSERT((String::kMaxLength & 0x80000000) == 0); |
7569 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | 7806 ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
7570 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | 7807 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
7571 __ cmp(r6, Operand(String::kMaxLength + 1)); | 7808 __ cmp(r6, Operand(String::kMaxLength + 1)); |
7572 __ b(hs, &string_add_runtime); | 7809 __ b(hs, &string_add_runtime); |
7573 | 7810 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7632 ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test. | 7869 ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test. |
7633 __ eor(r7, r4, Operand(r5)); | 7870 __ eor(r7, r4, Operand(r5)); |
7634 __ tst(r7, Operand(kStringEncodingMask)); | 7871 __ tst(r7, Operand(kStringEncodingMask)); |
7635 __ b(ne, &string_add_runtime); | 7872 __ b(ne, &string_add_runtime); |
7636 // And see if it's ASCII or two-byte. | 7873 // And see if it's ASCII or two-byte. |
7637 __ tst(r4, Operand(kStringEncodingMask)); | 7874 __ tst(r4, Operand(kStringEncodingMask)); |
7638 __ b(eq, &non_ascii_string_add_flat_result); | 7875 __ b(eq, &non_ascii_string_add_flat_result); |
7639 | 7876 |
7640 // Both strings are sequential ASCII strings. We also know that they are | 7877 // Both strings are sequential ASCII strings. We also know that they are |
7641 // short (since the sum of the lengths is less than kMinNonFlatLength). | 7878 // short (since the sum of the lengths is less than kMinNonFlatLength). |
| 7879 // r6: length of resulting flat string |
7642 __ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime); | 7880 __ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime); |
7643 // Locate first character of result. | 7881 // Locate first character of result. |
7644 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 7882 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
7645 // Locate first character of first argument. | 7883 // Locate first character of first argument. |
7646 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 7884 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
7647 // r0: first character of first string. | 7885 // r0: first character of first string. |
7648 // r1: second string. | 7886 // r1: second string. |
7649 // r2: length of first string. | 7887 // r2: length of first string. |
7650 // r3: length of second string. | 7888 // r3: length of second string. |
7651 // r6: first character of result. | 7889 // r6: first character of result. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7707 | 7945 |
7708 // Just jump to runtime to add the two strings. | 7946 // Just jump to runtime to add the two strings. |
7709 __ bind(&string_add_runtime); | 7947 __ bind(&string_add_runtime); |
7710 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 7948 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
7711 } | 7949 } |
7712 | 7950 |
7713 | 7951 |
7714 #undef __ | 7952 #undef __ |
7715 | 7953 |
7716 } } // namespace v8::internal | 7954 } } // namespace v8::internal |
OLD | NEW |