OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 6122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6133 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5); | 6133 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5); |
6134 | 6134 |
6135 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 6135 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
6136 // tagged as a small integer. | 6136 // tagged as a small integer. |
6137 __ bind(&runtime); | 6137 __ bind(&runtime); |
6138 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 6138 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
6139 } | 6139 } |
6140 | 6140 |
6141 | 6141 |
6142 void StringAddStub::Generate(MacroAssembler* masm) { | 6142 void StringAddStub::Generate(MacroAssembler* masm) { |
6143 Label string_add_runtime, call_builtin; | 6143 Label call_runtime, call_builtin; |
6144 Builtins::JavaScript builtin_id = Builtins::ADD; | 6144 Builtins::JavaScript builtin_id = Builtins::ADD; |
6145 | 6145 |
6146 Counters* counters = masm->isolate()->counters(); | 6146 Counters* counters = masm->isolate()->counters(); |
6147 | 6147 |
6148 // Stack on entry: | 6148 // Stack on entry: |
6149 // sp[0]: second argument (right). | 6149 // sp[0]: second argument (right). |
6150 // sp[4]: first argument (left). | 6150 // sp[4]: first argument (left). |
6151 | 6151 |
6152 // Load the two arguments. | 6152 // Load the two arguments. |
6153 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. | 6153 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. |
6154 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. | 6154 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. |
6155 | 6155 |
6156 // Make sure that both arguments are strings if not known in advance. | 6156 // Make sure that both arguments are strings if not known in advance. |
6157 if (flags_ == NO_STRING_ADD_FLAGS) { | 6157 if (flags_ == NO_STRING_ADD_FLAGS) { |
6158 __ JumpIfEitherSmi(r0, r1, &string_add_runtime); | 6158 __ JumpIfEitherSmi(r0, r1, &call_runtime); |
6159 // Load instance types. | 6159 // Load instance types. |
6160 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 6160 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
6161 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 6161 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
6162 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 6162 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
6163 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 6163 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
6164 STATIC_ASSERT(kStringTag == 0); | 6164 STATIC_ASSERT(kStringTag == 0); |
6165 // If either is not a string, go to runtime. | 6165 // If either is not a string, go to runtime. |
6166 __ tst(r4, Operand(kIsNotStringMask)); | 6166 __ tst(r4, Operand(kIsNotStringMask)); |
6167 __ tst(r5, Operand(kIsNotStringMask), eq); | 6167 __ tst(r5, Operand(kIsNotStringMask), eq); |
6168 __ b(ne, &string_add_runtime); | 6168 __ b(ne, &call_runtime); |
6169 } else { | 6169 } else { |
6170 // Here at least one of the arguments is definitely a string. | 6170 // Here at least one of the arguments is definitely a string. |
6171 // We convert the one that is not known to be a string. | 6171 // We convert the one that is not known to be a string. |
6172 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 6172 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { |
6173 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 6173 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); |
6174 GenerateConvertArgument( | 6174 GenerateConvertArgument( |
6175 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin); | 6175 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin); |
6176 builtin_id = Builtins::STRING_ADD_RIGHT; | 6176 builtin_id = Builtins::STRING_ADD_RIGHT; |
6177 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 6177 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { |
6178 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 6178 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6227 __ b(ne, &longer_than_two); | 6227 __ b(ne, &longer_than_two); |
6228 | 6228 |
6229 // Check that both strings are non-external ASCII strings. | 6229 // Check that both strings are non-external ASCII strings. |
6230 if (flags_ != NO_STRING_ADD_FLAGS) { | 6230 if (flags_ != NO_STRING_ADD_FLAGS) { |
6231 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 6231 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
6232 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 6232 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
6233 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 6233 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
6234 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 6234 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
6235 } | 6235 } |
6236 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, | 6236 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, |
6237 &string_add_runtime); | 6237 &call_runtime); |
6238 | 6238 |
6239 // Get the two characters forming the sub string. | 6239 // Get the two characters forming the sub string. |
6240 __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); | 6240 __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
6241 __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); | 6241 __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); |
6242 | 6242 |
6243 // Try to lookup two character string in symbol table. If it is not found | 6243 // Try to lookup two character string in symbol table. If it is not found |
6244 // just allocate a new one. | 6244 // just allocate a new one. |
6245 Label make_two_character_string; | 6245 Label make_two_character_string; |
6246 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 6246 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
6247 masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string); | 6247 masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string); |
6248 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | 6248 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); |
6249 __ add(sp, sp, Operand(2 * kPointerSize)); | 6249 __ add(sp, sp, Operand(2 * kPointerSize)); |
6250 __ Ret(); | 6250 __ Ret(); |
6251 | 6251 |
6252 __ bind(&make_two_character_string); | 6252 __ bind(&make_two_character_string); |
6253 // Resulting string has length 2 and first chars of two strings | 6253 // Resulting string has length 2 and first chars of two strings |
6254 // are combined into single halfword in r2 register. | 6254 // are combined into single halfword in r2 register. |
6255 // So we can fill resulting string without two loops by a single | 6255 // So we can fill resulting string without two loops by a single |
6256 // halfword store instruction (which assumes that processor is | 6256 // halfword store instruction (which assumes that processor is |
6257 // in a little endian mode) | 6257 // in a little endian mode) |
6258 __ mov(r6, Operand(2)); | 6258 __ mov(r6, Operand(2)); |
6259 __ AllocateAsciiString(r0, r6, r4, r5, r9, &string_add_runtime); | 6259 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); |
6260 __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); | 6260 __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
6261 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | 6261 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); |
6262 __ add(sp, sp, Operand(2 * kPointerSize)); | 6262 __ add(sp, sp, Operand(2 * kPointerSize)); |
6263 __ Ret(); | 6263 __ Ret(); |
6264 | 6264 |
6265 __ bind(&longer_than_two); | 6265 __ bind(&longer_than_two); |
6266 // Check if resulting string will be flat. | 6266 // Check if resulting string will be flat. |
6267 __ cmp(r6, Operand(String::kMinNonFlatLength)); | 6267 __ cmp(r6, Operand(String::kMinNonFlatLength)); |
6268 __ b(lt, &string_add_flat_result); | 6268 __ b(lt, &string_add_flat_result); |
6269 // Handle exceptionally long strings in the runtime system. | 6269 // Handle exceptionally long strings in the runtime system. |
6270 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | 6270 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); |
6271 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | 6271 ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
6272 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | 6272 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
6273 __ cmp(r6, Operand(String::kMaxLength + 1)); | 6273 __ cmp(r6, Operand(String::kMaxLength + 1)); |
6274 __ b(hs, &string_add_runtime); | 6274 __ b(hs, &call_runtime); |
6275 | 6275 |
6276 // If result is not supposed to be flat, allocate a cons string object. | 6276 // If result is not supposed to be flat, allocate a cons string object. |
6277 // If both strings are ASCII the result is an ASCII cons string. | 6277 // If both strings are ASCII the result is an ASCII cons string. |
6278 if (flags_ != NO_STRING_ADD_FLAGS) { | 6278 if (flags_ != NO_STRING_ADD_FLAGS) { |
6279 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 6279 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
6280 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 6280 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
6281 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 6281 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
6282 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 6282 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
6283 } | 6283 } |
6284 Label non_ascii, allocated, ascii_data; | 6284 Label non_ascii, allocated, ascii_data; |
6285 STATIC_ASSERT(kTwoByteStringTag == 0); | 6285 STATIC_ASSERT(kTwoByteStringTag == 0); |
6286 __ tst(r4, Operand(kStringEncodingMask)); | 6286 __ tst(r4, Operand(kStringEncodingMask)); |
6287 __ tst(r5, Operand(kStringEncodingMask), ne); | 6287 __ tst(r5, Operand(kStringEncodingMask), ne); |
6288 __ b(eq, &non_ascii); | 6288 __ b(eq, &non_ascii); |
6289 | 6289 |
6290 // Allocate an ASCII cons string. | 6290 // Allocate an ASCII cons string. |
6291 __ bind(&ascii_data); | 6291 __ bind(&ascii_data); |
6292 __ AllocateAsciiConsString(r7, r6, r4, r5, &string_add_runtime); | 6292 __ AllocateAsciiConsString(r7, r6, r4, r5, &call_runtime); |
6293 __ bind(&allocated); | 6293 __ bind(&allocated); |
6294 // Fill the fields of the cons string. | 6294 // Fill the fields of the cons string. |
6295 __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset)); | 6295 __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset)); |
6296 __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset)); | 6296 __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset)); |
6297 __ mov(r0, Operand(r7)); | 6297 __ mov(r0, Operand(r7)); |
6298 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | 6298 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); |
6299 __ add(sp, sp, Operand(2 * kPointerSize)); | 6299 __ add(sp, sp, Operand(2 * kPointerSize)); |
6300 __ Ret(); | 6300 __ Ret(); |
6301 | 6301 |
6302 __ bind(&non_ascii); | 6302 __ bind(&non_ascii); |
6303 // At least one of the strings is two-byte. Check whether it happens | 6303 // At least one of the strings is two-byte. Check whether it happens |
6304 // to contain only ASCII characters. | 6304 // to contain only ASCII characters. |
6305 // r4: first instance type. | 6305 // r4: first instance type. |
6306 // r5: second instance type. | 6306 // r5: second instance type. |
6307 __ tst(r4, Operand(kAsciiDataHintMask)); | 6307 __ tst(r4, Operand(kAsciiDataHintMask)); |
6308 __ tst(r5, Operand(kAsciiDataHintMask), ne); | 6308 __ tst(r5, Operand(kAsciiDataHintMask), ne); |
6309 __ b(ne, &ascii_data); | 6309 __ b(ne, &ascii_data); |
6310 __ eor(r4, r4, Operand(r5)); | 6310 __ eor(r4, r4, Operand(r5)); |
6311 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 6311 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |
6312 __ and_(r4, r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); | 6312 __ and_(r4, r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); |
6313 __ cmp(r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); | 6313 __ cmp(r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); |
6314 __ b(eq, &ascii_data); | 6314 __ b(eq, &ascii_data); |
6315 | 6315 |
6316 // Allocate a two byte cons string. | 6316 // Allocate a two byte cons string. |
6317 __ AllocateTwoByteConsString(r7, r6, r4, r5, &string_add_runtime); | 6317 __ AllocateTwoByteConsString(r7, r6, r4, r5, &call_runtime); |
6318 __ jmp(&allocated); | 6318 __ jmp(&allocated); |
6319 | 6319 |
6320 // Handle creating a flat result. First check that both strings are | 6320 // We cannot encounter sliced strings or cons strings here since: |
6321 // sequential and that they have the same encoding. | 6321 STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); |
| 6322 // Handle creating a flat result from either external or sequential strings. |
| 6323 // Locate the first characters' locations. |
6322 // r0: first string | 6324 // r0: first string |
6323 // r1: second string | 6325 // r1: second string |
6324 // r2: length of first string | 6326 // r2: length of first string |
6325 // r3: length of second string | 6327 // r3: length of second string |
6326 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 6328 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
6327 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 6329 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
6328 // r6: sum of lengths. | 6330 // r6: sum of lengths. |
| 6331 Label first_prepared, second_prepared; |
6329 __ bind(&string_add_flat_result); | 6332 __ bind(&string_add_flat_result); |
6330 if (flags_ != NO_STRING_ADD_FLAGS) { | 6333 if (flags_ != NO_STRING_ADD_FLAGS) { |
6331 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 6334 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
6332 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 6335 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
6333 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 6336 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
6334 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 6337 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
6335 } | 6338 } |
6336 // Check that both strings are sequential. | 6339 |
| 6340 // Check whether both strings have same encoding |
| 6341 __ eor(r7, r4, Operand(r5)); |
| 6342 __ tst(r7, Operand(kStringEncodingMask)); |
| 6343 __ b(ne, &call_runtime); |
| 6344 |
6337 STATIC_ASSERT(kSeqStringTag == 0); | 6345 STATIC_ASSERT(kSeqStringTag == 0); |
6338 __ tst(r4, Operand(kStringRepresentationMask)); | 6346 __ tst(r4, Operand(kStringRepresentationMask)); |
6339 __ tst(r5, Operand(kStringRepresentationMask), eq); | 6347 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
6340 __ b(ne, &string_add_runtime); | 6348 __ add(r7, |
6341 // Now check if both strings have the same encoding (ASCII/Two-byte). | 6349 r0, |
6342 // r0: first string. | 6350 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag), |
6343 // r1: second string. | 6351 LeaveCC, |
| 6352 eq); |
| 6353 __ b(eq, &first_prepared); |
| 6354 // External string: rule out short external string and load string resource. |
| 6355 STATIC_ASSERT(kShortExternalStringTag != 0); |
| 6356 __ tst(r4, Operand(kShortExternalStringMask)); |
| 6357 __ b(ne, &call_runtime); |
| 6358 __ ldr(r7, FieldMemOperand(r0, ExternalString::kResourceDataOffset)); |
| 6359 __ bind(&first_prepared); |
| 6360 |
| 6361 STATIC_ASSERT(kSeqStringTag == 0); |
| 6362 __ tst(r5, Operand(kStringRepresentationMask)); |
| 6363 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
| 6364 __ add(r1, |
| 6365 r1, |
| 6366 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag), |
| 6367 LeaveCC, |
| 6368 eq); |
| 6369 __ b(eq, &second_prepared); |
| 6370 // External string: rule out short external string and load string resource. |
| 6371 STATIC_ASSERT(kShortExternalStringTag != 0); |
| 6372 __ tst(r5, Operand(kShortExternalStringMask)); |
| 6373 __ b(ne, &call_runtime); |
| 6374 __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset)); |
| 6375 __ bind(&second_prepared); |
| 6376 |
| 6377 Label non_ascii_string_add_flat_result; |
| 6378 // r7: first character of first string |
| 6379 // r1: first character of second string |
6344 // r2: length of first string. | 6380 // r2: length of first string. |
6345 // r3: length of second string. | 6381 // r3: length of second string. |
6346 // r6: sum of lengths.. | 6382 // r6: sum of lengths. |
6347 Label non_ascii_string_add_flat_result; | 6383 // Both strings have the same encoding. |
6348 ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test. | 6384 STATIC_ASSERT(kTwoByteStringTag == 0); |
6349 __ eor(r7, r4, Operand(r5)); | 6385 __ tst(r5, Operand(kStringEncodingMask)); |
6350 __ tst(r7, Operand(kStringEncodingMask)); | |
6351 __ b(ne, &string_add_runtime); | |
6352 // And see if it's ASCII or two-byte. | |
6353 __ tst(r4, Operand(kStringEncodingMask)); | |
6354 __ b(eq, &non_ascii_string_add_flat_result); | 6386 __ b(eq, &non_ascii_string_add_flat_result); |
6355 | 6387 |
6356 // Both strings are sequential ASCII strings. We also know that they are | 6388 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); |
6357 // short (since the sum of the lengths is less than kMinNonFlatLength). | 6389 __ add(r6, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
6358 // r6: length of resulting flat string | 6390 // r0: result string. |
6359 __ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime); | 6391 // r7: first character of first string. |
6360 // Locate first character of result. | 6392 // r1: first character of second string. |
6361 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
6362 // Locate first character of first argument. | |
6363 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
6364 // r0: first character of first string. | |
6365 // r1: second string. | |
6366 // r2: length of first string. | 6393 // r2: length of first string. |
6367 // r3: length of second string. | 6394 // r3: length of second string. |
6368 // r6: first character of result. | 6395 // r6: first character of result. |
6369 // r7: result string. | 6396 StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, true); |
6370 StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, true); | |
6371 | |
6372 // Load second argument and locate first character. | |
6373 __ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
6374 // r1: first character of second string. | |
6375 // r3: length of second string. | |
6376 // r6: next character of result. | 6397 // r6: next character of result. |
6377 // r7: result string. | |
6378 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true); | 6398 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true); |
6379 __ mov(r0, Operand(r7)); | |
6380 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | 6399 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); |
6381 __ add(sp, sp, Operand(2 * kPointerSize)); | 6400 __ add(sp, sp, Operand(2 * kPointerSize)); |
6382 __ Ret(); | 6401 __ Ret(); |
6383 | 6402 |
6384 __ bind(&non_ascii_string_add_flat_result); | 6403 __ bind(&non_ascii_string_add_flat_result); |
6385 // Both strings are sequential two byte strings. | 6404 __ AllocateTwoByteString(r0, r6, r4, r5, r9, &call_runtime); |
6386 // r0: first string. | 6405 __ add(r6, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
6387 // r1: second string. | 6406 // r0: result string. |
6388 // r2: length of first string. | 6407 // r7: first character of first string. |
6389 // r3: length of second string. | 6408 // r1: first character of second string. |
6390 // r6: sum of length of strings. | |
6391 __ AllocateTwoByteString(r7, r6, r4, r5, r9, &string_add_runtime); | |
6392 // r0: first string. | |
6393 // r1: second string. | |
6394 // r2: length of first string. | |
6395 // r3: length of second string. | |
6396 // r7: result string. | |
6397 | |
6398 // Locate first character of result. | |
6399 __ add(r6, r7, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
6400 // Locate first character of first argument. | |
6401 __ add(r0, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
6402 | |
6403 // r0: first character of first string. | |
6404 // r1: second string. | |
6405 // r2: length of first string. | 6409 // r2: length of first string. |
6406 // r3: length of second string. | 6410 // r3: length of second string. |
6407 // r6: first character of result. | 6411 // r6: first character of result. |
6408 // r7: result string. | 6412 StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, false); |
6409 StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, false); | 6413 // r6: next character of result. |
6410 | |
6411 // Locate first character of second argument. | |
6412 __ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
6413 | |
6414 // r1: first character of second string. | |
6415 // r3: length of second string. | |
6416 // r6: next character of result (after copy of first string). | |
6417 // r7: result string. | |
6418 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false); | 6414 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false); |
6419 | |
6420 __ mov(r0, Operand(r7)); | |
6421 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | 6415 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); |
6422 __ add(sp, sp, Operand(2 * kPointerSize)); | 6416 __ add(sp, sp, Operand(2 * kPointerSize)); |
6423 __ Ret(); | 6417 __ Ret(); |
6424 | 6418 |
6425 // Just jump to runtime to add the two strings. | 6419 // Just jump to runtime to add the two strings. |
6426 __ bind(&string_add_runtime); | 6420 __ bind(&call_runtime); |
6427 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 6421 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
6428 | 6422 |
6429 if (call_builtin.is_linked()) { | 6423 if (call_builtin.is_linked()) { |
6430 __ bind(&call_builtin); | 6424 __ bind(&call_builtin); |
6431 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 6425 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
6432 } | 6426 } |
6433 } | 6427 } |
6434 | 6428 |
6435 | 6429 |
6436 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | 6430 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, |
(...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7316 __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10, | 7310 __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10, |
7317 &slow_elements); | 7311 &slow_elements); |
7318 __ Ret(); | 7312 __ Ret(); |
7319 } | 7313 } |
7320 | 7314 |
7321 #undef __ | 7315 #undef __ |
7322 | 7316 |
7323 } } // namespace v8::internal | 7317 } } // namespace v8::internal |
7324 | 7318 |
7325 #endif // V8_TARGET_ARCH_ARM | 7319 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |