Index: runtime/vm/intrinsifier_ia32.cc |
=================================================================== |
--- runtime/vm/intrinsifier_ia32.cc (revision 21228) |
+++ runtime/vm/intrinsifier_ia32.cc (working copy) |
@@ -1498,6 +1498,118 @@ |
return true; |
} |
+ |
+// 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) { |
+ __ movl(EDI, Address(ESP, + end_index_offset)); |
+ __ subl(EDI, Address(ESP, + start_index_offset)); |
+ const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; |
+ __ SmiUntag(EDI); |
+ __ leal(EDI, Address(EDI, TIMES_1, fixed_size)); // EDI is a Smi. |
+ __ andl(EDI, Immediate(-kObjectAlignment)); |
+ |
+ Isolate* isolate = Isolate::Current(); |
+ Heap* heap = isolate->heap(); |
+ |
+ __ movl(EAX, Address::Absolute(heap->TopAddress())); |
+ __ movl(EBX, EAX); |
+ |
+ // EDI: allocation size. |
+ __ addl(EBX, EDI); |
+ __ j(CARRY, failure); |
+ |
+ // Check if the allocation fits into the remaining space. |
+ // EAX: potential new object start. |
+ // EBX: potential next object start. |
+ // EDI: allocation size. |
+ __ cmpl(EBX, Address::Absolute(heap->EndAddress())); |
+ __ j(ABOVE_EQUAL, failure); |
+ |
+ // Successfully allocated the object(s), now update top to point to |
+ // next object start and initialize the object. |
+ __ movl(Address::Absolute(heap->TopAddress()), EBX); |
+ __ addl(EAX, Immediate(kHeapObjectTag)); |
+ |
+ // Initialize the tags. |
+ // EAX: new object start as a tagged pointer. |
+ // EBX: new object end address. |
+ // EDI: allocation size. |
+ { |
+ Label size_tag_overflow, done; |
+ __ cmpl(EDI, Immediate(RawObject::SizeTag::kMaxSizeTag)); |
+ __ j(ABOVE, &size_tag_overflow, Assembler::kNearJump); |
+ __ shll(EDI, Immediate(RawObject::kSizeTagBit - kObjectAlignmentLog2)); |
+ __ jmp(&done, Assembler::kNearJump); |
+ |
+ __ Bind(&size_tag_overflow); |
+ __ xorl(EDI, EDI); |
+ __ Bind(&done); |
+ |
+ // Get the class index and insert it into the tags. |
+ const Class& cls = |
+ Class::Handle(isolate->object_store()->one_byte_string_class()); |
+ __ orl(EDI, Immediate(RawObject::ClassIdTag::encode(cls.id()))); |
+ __ movl(FieldAddress(EAX, String::tags_offset()), EDI); // Tags. |
+ } |
+ |
+ // Set the length field. |
+ __ movl(EDI, Address(ESP, + end_index_offset)); |
+ __ subl(EDI, Address(ESP, + start_index_offset)); // Length. |
+ __ StoreIntoObjectNoBarrier(EAX, |
+ FieldAddress(EAX, String::length_offset()), |
+ EDI); |
+ // Clear hash. |
+ __ movl(FieldAddress(EAX, 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); |
+ // EAX: new string as tagged pointer. |
+ // Copy string. |
+ __ movl(EDI, Address(ESP, + kStringOffset)); |
+ __ movl(EBX, Address(ESP, + kStartIndexOffset)); |
+ __ SmiUntag(EBX); |
+ __ leal(EDI, FieldAddress(EDI, EBX, TIMES_1, OneByteString::data_offset())); |
+ // EDI: Start address to copy from (untagged). |
+ __ movl(EDX, Address(ESP, + kEndIndexOffset)); |
+ __ SmiUntag(EDX); |
+ __ subl(EDX, EBX); |
+ __ xorl(ECX, ECX); |
+ // EDX: Number of bytes to copy. |
+ // ECX: 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(EBX, Address(EDI, ECX, TIMES_1, 0)); |
+ __ movb(FieldAddress(EAX, ECX, TIMES_1, OneByteString::data_offset()), BL); |
+ __ incl(ECX); |
+ __ Bind(&check); |
+ __ cmpl(ECX, EDX); |
+ __ j(LESS, &loop, Assembler::kNearJump); |
+ |
+ __ Bind(&done); |
+ __ ret(); |
+ __ Bind(&fall_through); |
+ return false; |
+} |
+ |
#undef __ |
} // namespace dart |