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 6399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6410 __ IncrementCounter(counters->string_compare_native(), 1, a2, a3); | 6410 __ IncrementCounter(counters->string_compare_native(), 1, a2, a3); |
6411 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 6411 __ Addu(sp, sp, Operand(2 * kPointerSize)); |
6412 GenerateCompareFlatAsciiStrings(masm, a1, a0, a2, a3, t0, t1); | 6412 GenerateCompareFlatAsciiStrings(masm, a1, a0, a2, a3, t0, t1); |
6413 | 6413 |
6414 __ bind(&runtime); | 6414 __ bind(&runtime); |
6415 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 6415 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
6416 } | 6416 } |
6417 | 6417 |
6418 | 6418 |
6419 void StringAddStub::Generate(MacroAssembler* masm) { | 6419 void StringAddStub::Generate(MacroAssembler* masm) { |
6420 Label string_add_runtime, call_builtin; | 6420 Label call_runtime, call_builtin; |
6421 Builtins::JavaScript builtin_id = Builtins::ADD; | 6421 Builtins::JavaScript builtin_id = Builtins::ADD; |
6422 | 6422 |
6423 Counters* counters = masm->isolate()->counters(); | 6423 Counters* counters = masm->isolate()->counters(); |
6424 | 6424 |
6425 // Stack on entry: | 6425 // Stack on entry: |
6426 // sp[0]: second argument (right). | 6426 // sp[0]: second argument (right). |
6427 // sp[4]: first argument (left). | 6427 // sp[4]: first argument (left). |
6428 | 6428 |
6429 // Load the two arguments. | 6429 // Load the two arguments. |
6430 __ lw(a0, MemOperand(sp, 1 * kPointerSize)); // First argument. | 6430 __ lw(a0, MemOperand(sp, 1 * kPointerSize)); // First argument. |
6431 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); // Second argument. | 6431 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); // Second argument. |
6432 | 6432 |
6433 // Make sure that both arguments are strings if not known in advance. | 6433 // Make sure that both arguments are strings if not known in advance. |
6434 if (flags_ == NO_STRING_ADD_FLAGS) { | 6434 if (flags_ == NO_STRING_ADD_FLAGS) { |
6435 __ JumpIfEitherSmi(a0, a1, &string_add_runtime); | 6435 __ JumpIfEitherSmi(a0, a1, &call_runtime); |
6436 // Load instance types. | 6436 // Load instance types. |
6437 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 6437 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
6438 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 6438 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
6439 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 6439 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
6440 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 6440 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
6441 STATIC_ASSERT(kStringTag == 0); | 6441 STATIC_ASSERT(kStringTag == 0); |
6442 // If either is not a string, go to runtime. | 6442 // If either is not a string, go to runtime. |
6443 __ Or(t4, t0, Operand(t1)); | 6443 __ Or(t4, t0, Operand(t1)); |
6444 __ And(t4, t4, Operand(kIsNotStringMask)); | 6444 __ And(t4, t4, Operand(kIsNotStringMask)); |
6445 __ Branch(&string_add_runtime, ne, t4, Operand(zero_reg)); | 6445 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); |
6446 } else { | 6446 } else { |
6447 // Here at least one of the arguments is definitely a string. | 6447 // Here at least one of the arguments is definitely a string. |
6448 // We convert the one that is not known to be a string. | 6448 // We convert the one that is not known to be a string. |
6449 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 6449 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { |
6450 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 6450 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); |
6451 GenerateConvertArgument( | 6451 GenerateConvertArgument( |
6452 masm, 1 * kPointerSize, a0, a2, a3, t0, t1, &call_builtin); | 6452 masm, 1 * kPointerSize, a0, a2, a3, t0, t1, &call_builtin); |
6453 builtin_id = Builtins::STRING_ADD_RIGHT; | 6453 builtin_id = Builtins::STRING_ADD_RIGHT; |
6454 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 6454 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { |
6455 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 6455 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); |
(...skipping 18 matching lines...) Expand all Loading... |
6474 __ lw(a2, FieldMemOperand(a0, String::kLengthOffset)); | 6474 __ lw(a2, FieldMemOperand(a0, String::kLengthOffset)); |
6475 __ lw(a3, FieldMemOperand(a1, String::kLengthOffset)); | 6475 __ lw(a3, FieldMemOperand(a1, String::kLengthOffset)); |
6476 __ mov(v0, a0); // Assume we'll return first string (from a0). | 6476 __ mov(v0, a0); // Assume we'll return first string (from a0). |
6477 __ movz(v0, a1, a2); // If first is empty, return second (from a1). | 6477 __ movz(v0, a1, a2); // If first is empty, return second (from a1). |
6478 __ slt(t4, zero_reg, a2); // if (a2 > 0) t4 = 1. | 6478 __ slt(t4, zero_reg, a2); // if (a2 > 0) t4 = 1. |
6479 __ slt(t5, zero_reg, a3); // if (a3 > 0) t5 = 1. | 6479 __ slt(t5, zero_reg, a3); // if (a3 > 0) t5 = 1. |
6480 __ and_(t4, t4, t5); // Branch if both strings were non-empty. | 6480 __ and_(t4, t4, t5); // Branch if both strings were non-empty. |
6481 __ Branch(&strings_not_empty, ne, t4, Operand(zero_reg)); | 6481 __ Branch(&strings_not_empty, ne, t4, Operand(zero_reg)); |
6482 | 6482 |
6483 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | 6483 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
6484 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 6484 __ DropAndRet(2); |
6485 __ Ret(); | |
6486 | 6485 |
6487 __ bind(&strings_not_empty); | 6486 __ bind(&strings_not_empty); |
6488 } | 6487 } |
6489 | 6488 |
6490 // Untag both string-lengths. | 6489 // Untag both string-lengths. |
6491 __ sra(a2, a2, kSmiTagSize); | 6490 __ sra(a2, a2, kSmiTagSize); |
6492 __ sra(a3, a3, kSmiTagSize); | 6491 __ sra(a3, a3, kSmiTagSize); |
6493 | 6492 |
6494 // Both strings are non-empty. | 6493 // Both strings are non-empty. |
6495 // a0: first string | 6494 // a0: first string |
(...skipping 12 matching lines...) Expand all Loading... |
6508 __ Branch(&longer_than_two, ne, t2, Operand(2)); | 6507 __ Branch(&longer_than_two, ne, t2, Operand(2)); |
6509 | 6508 |
6510 // Check that both strings are non-external ASCII strings. | 6509 // Check that both strings are non-external ASCII strings. |
6511 if (flags_ != NO_STRING_ADD_FLAGS) { | 6510 if (flags_ != NO_STRING_ADD_FLAGS) { |
6512 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 6511 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
6513 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 6512 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
6514 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 6513 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
6515 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 6514 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
6516 } | 6515 } |
6517 __ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3, | 6516 __ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3, |
6518 &string_add_runtime); | 6517 &call_runtime); |
6519 | 6518 |
6520 // Get the two characters forming the sub string. | 6519 // Get the two characters forming the sub string. |
6521 __ lbu(a2, FieldMemOperand(a0, SeqAsciiString::kHeaderSize)); | 6520 __ lbu(a2, FieldMemOperand(a0, SeqAsciiString::kHeaderSize)); |
6522 __ lbu(a3, FieldMemOperand(a1, SeqAsciiString::kHeaderSize)); | 6521 __ lbu(a3, FieldMemOperand(a1, SeqAsciiString::kHeaderSize)); |
6523 | 6522 |
6524 // Try to lookup two character string in symbol table. If it is not found | 6523 // Try to lookup two character string in symbol table. If it is not found |
6525 // just allocate a new one. | 6524 // just allocate a new one. |
6526 Label make_two_character_string; | 6525 Label make_two_character_string; |
6527 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 6526 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
6528 masm, a2, a3, t2, t3, t0, t1, t4, &make_two_character_string); | 6527 masm, a2, a3, t2, t3, t0, t1, t5, &make_two_character_string); |
6529 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | 6528 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
6530 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 6529 __ DropAndRet(2); |
6531 __ Ret(); | |
6532 | 6530 |
6533 __ bind(&make_two_character_string); | 6531 __ bind(&make_two_character_string); |
6534 // Resulting string has length 2 and first chars of two strings | 6532 // Resulting string has length 2 and first chars of two strings |
6535 // are combined into single halfword in a2 register. | 6533 // are combined into single halfword in a2 register. |
6536 // So we can fill resulting string without two loops by a single | 6534 // So we can fill resulting string without two loops by a single |
6537 // halfword store instruction (which assumes that processor is | 6535 // halfword store instruction (which assumes that processor is |
6538 // in a little endian mode). | 6536 // in a little endian mode). |
6539 __ li(t2, Operand(2)); | 6537 __ li(t2, Operand(2)); |
6540 __ AllocateAsciiString(v0, t2, t0, t1, t4, &string_add_runtime); | 6538 __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); |
6541 __ sh(a2, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); | 6539 __ sh(a2, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); |
6542 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | 6540 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
6543 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 6541 __ DropAndRet(2); |
6544 __ Ret(); | |
6545 | 6542 |
6546 __ bind(&longer_than_two); | 6543 __ bind(&longer_than_two); |
6547 // Check if resulting string will be flat. | 6544 // Check if resulting string will be flat. |
6548 __ Branch(&string_add_flat_result, lt, t2, | 6545 __ Branch(&string_add_flat_result, lt, t2, |
6549 Operand(String::kMinNonFlatLength)); | 6546 Operand(String::kMinNonFlatLength)); |
6550 // Handle exceptionally long strings in the runtime system. | 6547 // Handle exceptionally long strings in the runtime system. |
6551 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | 6548 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); |
6552 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | 6549 ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
6553 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | 6550 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
6554 __ Branch(&string_add_runtime, hs, t2, Operand(String::kMaxLength + 1)); | 6551 __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1)); |
6555 | 6552 |
6556 // If result is not supposed to be flat, allocate a cons string object. | 6553 // If result is not supposed to be flat, allocate a cons string object. |
6557 // If both strings are ASCII the result is an ASCII cons string. | 6554 // If both strings are ASCII the result is an ASCII cons string. |
6558 if (flags_ != NO_STRING_ADD_FLAGS) { | 6555 if (flags_ != NO_STRING_ADD_FLAGS) { |
6559 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 6556 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
6560 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 6557 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
6561 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 6558 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
6562 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 6559 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
6563 } | 6560 } |
6564 Label non_ascii, allocated, ascii_data; | 6561 Label non_ascii, allocated, ascii_data; |
6565 STATIC_ASSERT(kTwoByteStringTag == 0); | 6562 STATIC_ASSERT(kTwoByteStringTag == 0); |
6566 // Branch to non_ascii if either string-encoding field is zero (non-ascii). | 6563 // Branch to non_ascii if either string-encoding field is zero (non-ascii). |
6567 __ And(t4, t0, Operand(t1)); | 6564 __ And(t4, t0, Operand(t1)); |
6568 __ And(t4, t4, Operand(kStringEncodingMask)); | 6565 __ And(t4, t4, Operand(kStringEncodingMask)); |
6569 __ Branch(&non_ascii, eq, t4, Operand(zero_reg)); | 6566 __ Branch(&non_ascii, eq, t4, Operand(zero_reg)); |
6570 | 6567 |
6571 // Allocate an ASCII cons string. | 6568 // Allocate an ASCII cons string. |
6572 __ bind(&ascii_data); | 6569 __ bind(&ascii_data); |
6573 __ AllocateAsciiConsString(t3, t2, t0, t1, &string_add_runtime); | 6570 __ AllocateAsciiConsString(v0, t2, t0, t1, &call_runtime); |
6574 __ bind(&allocated); | 6571 __ bind(&allocated); |
6575 // Fill the fields of the cons string. | 6572 // Fill the fields of the cons string. |
6576 __ sw(a0, FieldMemOperand(t3, ConsString::kFirstOffset)); | 6573 __ sw(a0, FieldMemOperand(v0, ConsString::kFirstOffset)); |
6577 __ sw(a1, FieldMemOperand(t3, ConsString::kSecondOffset)); | 6574 __ sw(a1, FieldMemOperand(v0, ConsString::kSecondOffset)); |
6578 __ mov(v0, t3); | |
6579 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | 6575 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
6580 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 6576 __ DropAndRet(2); |
6581 __ Ret(); | |
6582 | 6577 |
6583 __ bind(&non_ascii); | 6578 __ bind(&non_ascii); |
6584 // At least one of the strings is two-byte. Check whether it happens | 6579 // At least one of the strings is two-byte. Check whether it happens |
6585 // to contain only ASCII characters. | 6580 // to contain only ASCII characters. |
6586 // t0: first instance type. | 6581 // t0: first instance type. |
6587 // t1: second instance type. | 6582 // t1: second instance type. |
6588 // Branch to if _both_ instances have kAsciiDataHintMask set. | 6583 // Branch to if _both_ instances have kAsciiDataHintMask set. |
6589 __ And(at, t0, Operand(kAsciiDataHintMask)); | 6584 __ And(at, t0, Operand(kAsciiDataHintMask)); |
6590 __ and_(at, at, t1); | 6585 __ and_(at, at, t1); |
6591 __ Branch(&ascii_data, ne, at, Operand(zero_reg)); | 6586 __ Branch(&ascii_data, ne, at, Operand(zero_reg)); |
6592 | 6587 |
6593 __ xor_(t0, t0, t1); | 6588 __ xor_(t0, t0, t1); |
6594 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 6589 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |
6595 __ And(t0, t0, Operand(kAsciiStringTag | kAsciiDataHintTag)); | 6590 __ And(t0, t0, Operand(kAsciiStringTag | kAsciiDataHintTag)); |
6596 __ Branch(&ascii_data, eq, t0, Operand(kAsciiStringTag | kAsciiDataHintTag)); | 6591 __ Branch(&ascii_data, eq, t0, Operand(kAsciiStringTag | kAsciiDataHintTag)); |
6597 | 6592 |
6598 // Allocate a two byte cons string. | 6593 // Allocate a two byte cons string. |
6599 __ AllocateTwoByteConsString(t3, t2, t0, t1, &string_add_runtime); | 6594 __ AllocateTwoByteConsString(v0, t2, t0, t1, &call_runtime); |
6600 __ Branch(&allocated); | 6595 __ Branch(&allocated); |
6601 | 6596 |
6602 // Handle creating a flat result. First check that both strings are | 6597 // We cannot encounter sliced strings or cons strings here since: |
6603 // sequential and that they have the same encoding. | 6598 STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); |
| 6599 // Handle creating a flat result from either external or sequential strings. |
| 6600 // Locate the first characters' locations. |
6604 // a0: first string | 6601 // a0: first string |
6605 // a1: second string | 6602 // a1: second string |
6606 // a2: length of first string | 6603 // a2: length of first string |
6607 // a3: length of second string | 6604 // a3: length of second string |
6608 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 6605 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
6609 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 6606 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
6610 // t2: sum of lengths. | 6607 // t2: sum of lengths. |
| 6608 Label first_prepared, second_prepared; |
6611 __ bind(&string_add_flat_result); | 6609 __ bind(&string_add_flat_result); |
6612 if (flags_ != NO_STRING_ADD_FLAGS) { | 6610 if (flags_ != NO_STRING_ADD_FLAGS) { |
6613 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 6611 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
6614 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 6612 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
6615 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 6613 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
6616 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 6614 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
6617 } | 6615 } |
6618 // Check that both strings are sequential, meaning that we | 6616 // Check whether both strings have same encoding |
6619 // branch to runtime if either string tag is non-zero. | 6617 __ Xor(t3, t0, Operand(t1)); |
| 6618 __ And(t3, t3, Operand(kStringEncodingMask)); |
| 6619 __ Branch(&call_runtime, ne, t3, Operand(zero_reg)); |
| 6620 |
6620 STATIC_ASSERT(kSeqStringTag == 0); | 6621 STATIC_ASSERT(kSeqStringTag == 0); |
6621 __ Or(t4, t0, Operand(t1)); | 6622 __ And(t4, t0, Operand(kStringRepresentationMask)); |
6622 __ And(t4, t4, Operand(kStringRepresentationMask)); | |
6623 __ Branch(&string_add_runtime, ne, t4, Operand(zero_reg)); | |
6624 | 6623 |
6625 // Now check if both strings have the same encoding (ASCII/Two-byte). | 6624 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
6626 // a0: first string | 6625 Label skip_first_add; |
6627 // a1: second string | 6626 __ Branch(&skip_first_add, ne, t4, Operand(zero_reg)); |
| 6627 __ Branch(USE_DELAY_SLOT, &first_prepared); |
| 6628 __ addiu(t3, a0, SeqAsciiString::kHeaderSize - kHeapObjectTag); |
| 6629 __ bind(&skip_first_add); |
| 6630 // External string: rule out short external string and load string resource. |
| 6631 STATIC_ASSERT(kShortExternalStringTag != 0); |
| 6632 __ And(t4, t0, Operand(kShortExternalStringMask)); |
| 6633 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); |
| 6634 __ lw(t3, FieldMemOperand(a0, ExternalString::kResourceDataOffset)); |
| 6635 __ bind(&first_prepared); |
| 6636 |
| 6637 STATIC_ASSERT(kSeqStringTag == 0); |
| 6638 __ And(t4, t1, Operand(kStringRepresentationMask)); |
| 6639 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
| 6640 Label skip_second_add; |
| 6641 __ Branch(&skip_second_add, ne, t4, Operand(zero_reg)); |
| 6642 __ Branch(USE_DELAY_SLOT, &second_prepared); |
| 6643 __ addiu(a1, a1, SeqAsciiString::kHeaderSize - kHeapObjectTag); |
| 6644 __ bind(&skip_second_add); |
| 6645 // External string: rule out short external string and load string resource. |
| 6646 STATIC_ASSERT(kShortExternalStringTag != 0); |
| 6647 __ And(t4, t1, Operand(kShortExternalStringMask)); |
| 6648 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); |
| 6649 __ lw(a1, FieldMemOperand(a1, ExternalString::kResourceDataOffset)); |
| 6650 __ bind(&second_prepared); |
| 6651 |
| 6652 Label non_ascii_string_add_flat_result; |
| 6653 // t3: first character of first string |
| 6654 // a1: first character of second string |
6628 // a2: length of first string | 6655 // a2: length of first string |
6629 // a3: length of second string | 6656 // a3: length of second string |
6630 // t0: first string instance type | |
6631 // t1: second string instance type | |
6632 // t2: sum of lengths. | 6657 // t2: sum of lengths. |
6633 Label non_ascii_string_add_flat_result; | 6658 // Both strings have the same encoding. |
6634 ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test. | 6659 STATIC_ASSERT(kTwoByteStringTag == 0); |
6635 __ xor_(t3, t1, t0); | 6660 __ And(t4, t1, Operand(kStringEncodingMask)); |
6636 __ And(t3, t3, Operand(kStringEncodingMask)); | 6661 __ Branch(&non_ascii_string_add_flat_result, eq, t4, Operand(zero_reg)); |
6637 __ Branch(&string_add_runtime, ne, t3, Operand(zero_reg)); | |
6638 // And see if it's ASCII (0) or two-byte (1). | |
6639 __ And(t3, t0, Operand(kStringEncodingMask)); | |
6640 __ Branch(&non_ascii_string_add_flat_result, eq, t3, Operand(zero_reg)); | |
6641 | 6662 |
6642 // Both strings are sequential ASCII strings. We also know that they are | 6663 __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); |
6643 // short (since the sum of the lengths is less than kMinNonFlatLength). | 6664 __ Addu(t2, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
6644 // t2: length of resulting flat string | 6665 // v0: result string. |
6645 __ AllocateAsciiString(t3, t2, t0, t1, t4, &string_add_runtime); | 6666 // t3: first character of first string. |
6646 // Locate first character of result. | 6667 // a1: first character of second string |
6647 __ Addu(t2, t3, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
6648 // Locate first character of first argument. | |
6649 __ Addu(a0, a0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
6650 // a0: first character of first string. | |
6651 // a1: second string. | |
6652 // a2: length of first string. | 6668 // a2: length of first string. |
6653 // a3: length of second string. | 6669 // a3: length of second string. |
6654 // t2: first character of result. | 6670 // t2: first character of result. |
6655 // t3: result string. | |
6656 StringHelper::GenerateCopyCharacters(masm, t2, a0, a2, t0, true); | |
6657 | 6671 |
6658 // Load second argument and locate first character. | 6672 StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, true); |
6659 __ Addu(a1, a1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
6660 // a1: first character of second string. | |
6661 // a3: length of second string. | |
6662 // t2: next character of result. | 6673 // t2: next character of result. |
6663 // t3: result string. | |
6664 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, true); | 6674 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, true); |
6665 __ mov(v0, t3); | |
6666 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | 6675 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
6667 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 6676 __ DropAndRet(2); |
6668 __ Ret(); | |
6669 | 6677 |
6670 __ bind(&non_ascii_string_add_flat_result); | 6678 __ bind(&non_ascii_string_add_flat_result); |
6671 // Both strings are sequential two byte strings. | 6679 __ AllocateTwoByteString(v0, t2, t0, t1, t5, &call_runtime); |
6672 // a0: first string. | 6680 __ Addu(t2, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
6673 // a1: second string. | 6681 // v0: result string. |
6674 // a2: length of first string. | 6682 // t3: first character of first string. |
6675 // a3: length of second string. | 6683 // a1: first character of second string. |
6676 // t2: sum of length of strings. | |
6677 __ AllocateTwoByteString(t3, t2, t0, t1, t4, &string_add_runtime); | |
6678 // a0: first string. | |
6679 // a1: second string. | |
6680 // a2: length of first string. | |
6681 // a3: length of second string. | |
6682 // t3: result string. | |
6683 | |
6684 // Locate first character of result. | |
6685 __ Addu(t2, t3, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
6686 // Locate first character of first argument. | |
6687 __ Addu(a0, a0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
6688 | |
6689 // a0: first character of first string. | |
6690 // a1: second string. | |
6691 // a2: length of first string. | 6684 // a2: length of first string. |
6692 // a3: length of second string. | 6685 // a3: length of second string. |
6693 // t2: first character of result. | 6686 // t2: first character of result. |
6694 // t3: result string. | 6687 StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false); |
6695 StringHelper::GenerateCopyCharacters(masm, t2, a0, a2, t0, false); | 6688 // t2: next character of result. |
6696 | |
6697 // Locate first character of second argument. | |
6698 __ Addu(a1, a1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
6699 | |
6700 // a1: first character of second string. | |
6701 // a3: length of second string. | |
6702 // t2: next character of result (after copy of first string). | |
6703 // t3: result string. | |
6704 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false); | 6689 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false); |
6705 | 6690 |
6706 __ mov(v0, t3); | |
6707 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | 6691 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
6708 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 6692 __ DropAndRet(2); |
6709 __ Ret(); | |
6710 | 6693 |
6711 // Just jump to runtime to add the two strings. | 6694 // Just jump to runtime to add the two strings. |
6712 __ bind(&string_add_runtime); | 6695 __ bind(&call_runtime); |
6713 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 6696 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
6714 | 6697 |
6715 if (call_builtin.is_linked()) { | 6698 if (call_builtin.is_linked()) { |
6716 __ bind(&call_builtin); | 6699 __ bind(&call_builtin); |
6717 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 6700 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
6718 } | 6701 } |
6719 } | 6702 } |
6720 | 6703 |
6721 | 6704 |
6722 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | 6705 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, |
(...skipping 927 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7650 __ Ret(USE_DELAY_SLOT); | 7633 __ Ret(USE_DELAY_SLOT); |
7651 __ mov(v0, a0); | 7634 __ mov(v0, a0); |
7652 } | 7635 } |
7653 | 7636 |
7654 | 7637 |
7655 #undef __ | 7638 #undef __ |
7656 | 7639 |
7657 } } // namespace v8::internal | 7640 } } // namespace v8::internal |
7658 | 7641 |
7659 #endif // V8_TARGET_ARCH_MIPS | 7642 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |