Index: runtime/vm/intrinsifier_x64.cc |
=================================================================== |
--- runtime/vm/intrinsifier_x64.cc (revision 21228) |
+++ runtime/vm/intrinsifier_x64.cc (working copy) |
@@ -1420,6 +1420,120 @@ |
} |
+// Allocates one-byte string of length 'end - start'. The content is not |
+// initialized. |
+static void TryAllocateOnebyteString(Assembler* assembler, |
+ Label* failure, |
+ intptr_t start_index_offset, |
+ intptr_t end_index_offset) { |
+ __ movq(RDI, Address(RSP, + end_index_offset)); |
+ __ subq(RDI, Address(RSP, + start_index_offset)); |
+ const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; |
+ __ SmiUntag(RDI); |
+ __ leaq(RDI, Address(RDI, TIMES_1, fixed_size)); // RDI is a Smi. |
+ __ andq(RDI, Immediate(-kObjectAlignment)); |
+ |
+ Isolate* isolate = Isolate::Current(); |
+ Heap* heap = isolate->heap(); |
+ |
+ __ movq(RAX, Immediate(heap->TopAddress())); |
+ __ movq(RAX, Address(RAX, 0)); |
+ |
+ // RDI: allocation size. |
+ __ movq(RCX, RAX); |
+ __ addq(RCX, RDI); |
+ __ j(CARRY, failure); |
+ |
+ // Check if the allocation fits into the remaining space. |
+ // RAX: potential new object start. |
+ // RCX: potential next object start. |
+ // RDI: allocation size. |
+ __ movq(R13, Immediate(heap->EndAddress())); |
+ __ cmpq(RCX, Address(R13, 0)); |
+ __ j(ABOVE_EQUAL, failure); |
+ |
+ // Successfully allocated the object(s), now update top to point to |
+ // next object start and initialize the object. |
+ __ movq(R13, Immediate(heap->TopAddress())); |
+ __ movq(Address(R13, 0), RCX); |
+ __ addq(RAX, Immediate(kHeapObjectTag)); |
+ |
+ // Initialize the tags. |
+ // RAX: new object start as a tagged pointer. |
+ // RDI: allocation size. |
+ { |
+ Label size_tag_overflow, done; |
+ __ cmpq(RDI, Immediate(RawObject::SizeTag::kMaxSizeTag)); |
+ __ j(ABOVE, &size_tag_overflow, Assembler::kNearJump); |
+ __ shlq(RDI, Immediate(RawObject::kSizeTagBit - kObjectAlignmentLog2)); |
+ __ jmp(&done, Assembler::kNearJump); |
+ |
+ __ Bind(&size_tag_overflow); |
+ __ xorq(RDI, RDI); |
+ __ Bind(&done); |
+ |
+ // Get the class index and insert it into the tags. |
+ const Class& cls = |
+ Class::Handle(isolate->object_store()->one_byte_string_class()); |
+ __ orq(RDI, Immediate(RawObject::ClassIdTag::encode(cls.id()))); |
+ __ movq(FieldAddress(RAX, String::tags_offset()), RDI); // Tags. |
+ } |
+ |
+ // Set the length field. |
+ __ movq(RDI, Address(RSP, + end_index_offset)); |
+ __ subq(RDI, Address(RSP, + start_index_offset)); // Length. |
+ __ StoreIntoObjectNoBarrier(RAX, |
+ FieldAddress(RAX, String::length_offset()), |
+ RDI); |
+ // Clear hash. |
+ __ movq(FieldAddress(RAX, String::hash_offset()), Immediate(0)); |
+} |
+ |
+ |
+// Arg0: Onebyte String |
+// Arg1: Start index as Smi. |
+// Arg2: End index as Smi. |
+// The indexes must be valid. |
+bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
+ const intptr_t kStringOffset = 3 * kWordSize; |
+ const intptr_t kStartIndexOffset = 2 * kWordSize; |
+ const intptr_t kEndIndexOffset = 1 * kWordSize; |
+ Label fall_through, done; |
+ TryAllocateOnebyteString( |
+ assembler, &fall_through, kStartIndexOffset, kEndIndexOffset); |
+ // RAX: new string as tagged pointer. |
+ // Copy string. |
+ __ movq(RDI, Address(RSP, + kStringOffset)); |
+ __ movq(RBX, Address(RSP, + kStartIndexOffset)); |
+ __ SmiUntag(RBX); |
+ __ leaq(RDI, FieldAddress(RDI, RBX, TIMES_1, OneByteString::data_offset())); |
+ // RDI: Start address to copy from (untagged). |
+ __ movq(RDX, Address(RSP, + kEndIndexOffset)); |
+ __ SmiUntag(RDX); |
+ __ subq(RDX, RBX); |
+ __ xorq(RCX, RCX); |
+ // RDX: Number of bytes to copy. |
+ // RCX: Loop counter. |
+ // TODO(srdjan): For large substrings it could be better if we would group |
+ // the byte copies into word copies or even call memcpy. |
+ Label loop, check; |
+ // TODO(srdjan): Use rep movsb instead. |
+ __ jmp(&check, Assembler::kNearJump); |
+ __ Bind(&loop); |
+ __ movzxb(RBX, Address(RDI, RCX, TIMES_1, 0)); |
+ __ movb(FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset()), RBX); |
+ __ incq(RCX); |
+ __ Bind(&check); |
+ __ cmpq(RCX, RDX); |
+ __ j(LESS, &loop, Assembler::kNearJump); |
+ |
+ __ Bind(&done); |
+ __ ret(); |
+ __ Bind(&fall_through); |
+ return false; |
+} |
+ |
+ |
#undef __ |
} // namespace dart |