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