Skip to content

Commit 6ecd8a1

Browse files
askeksacommit-bot@chromium.org
authored andcommitted
[vm] MemoryCopy instruction for copying between typed data and strings.
Used for copying the bytes from the Uint8List to the _OneByteString in String.fromCharCodes and the pure-ASCII case of UTF-8 decoding. Issue #42072 Closes #41703 Change-Id: I1ae300222877d1c6e64e32c2f40b8fb187a584c0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/149500 Commit-Queue: Aske Simon Christensen <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent 41a7db1 commit 6ecd8a1

26 files changed

+936
-53
lines changed

runtime/vm/compiler/assembler/assembler_ia32.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,19 @@ void Assembler::rep_movsb() {
309309
EmitUint8(0xA4);
310310
}
311311

312+
void Assembler::rep_movsw() {
313+
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
314+
EmitUint8(0xF3);
315+
EmitUint8(0x66);
316+
EmitUint8(0xA5);
317+
}
318+
319+
void Assembler::rep_movsl() {
320+
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
321+
EmitUint8(0xF3);
322+
EmitUint8(0xA5);
323+
}
324+
312325
void Assembler::movss(XmmRegister dst, const Address& src) {
313326
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
314327
EmitUint8(0xF3);

runtime/vm/compiler/assembler/assembler_ia32.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ class Assembler : public AssemblerBase {
298298
void cmovlessl(Register dst, Register src);
299299

300300
void rep_movsb();
301+
void rep_movsw();
302+
void rep_movsl();
301303

302304
void movss(XmmRegister dst, const Address& src);
303305
void movss(const Address& dst, XmmRegister src);

runtime/vm/compiler/assembler/assembler_ia32_test.cc

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4755,14 +4755,16 @@ ASSEMBLER_TEST_GENERATE(TestRepMovsBytes, assembler) {
47554755
}
47564756

47574757
ASSEMBLER_TEST_RUN(TestRepMovsBytes, test) {
4758-
const char* from = "0123456789";
4759-
const char* to = new char[10];
4760-
typedef void (*TestRepMovsBytes)(const char* from, const char* to, int count);
4758+
const char* from = "0123456789x";
4759+
char* to = new char[11];
4760+
to[10] = 'y';
4761+
typedef void (*TestRepMovsBytes)(const char* from, char* to, int count);
47614762
reinterpret_cast<TestRepMovsBytes>(test->entry())(from, to, 10);
47624763
EXPECT_EQ(to[0], '0');
47634764
for (int i = 0; i < 10; i++) {
47644765
EXPECT_EQ(from[i], to[i]);
47654766
}
4767+
EXPECT_EQ(to[10], 'y');
47664768
delete[] to;
47674769
EXPECT_DISASSEMBLY(
47684770
"push esi\n"
@@ -4778,6 +4780,93 @@ ASSEMBLER_TEST_RUN(TestRepMovsBytes, test) {
47784780
"ret\n");
47794781
}
47804782

4783+
ASSEMBLER_TEST_GENERATE(TestRepMovsWords, assembler) {
4784+
// Preserve registers.
4785+
__ pushl(ESI);
4786+
__ pushl(EDI);
4787+
__ pushl(ECX);
4788+
__ movl(ESI, Address(ESP, 4 * target::kWordSize)); // from.
4789+
__ movl(EDI, Address(ESP, 5 * target::kWordSize)); // to.
4790+
__ movl(ECX, Address(ESP, 6 * target::kWordSize)); // count.
4791+
__ rep_movsw();
4792+
__ popl(ECX);
4793+
__ popl(EDI);
4794+
__ popl(ESI);
4795+
__ ret();
4796+
}
4797+
4798+
ASSEMBLER_TEST_RUN(TestRepMovsWords, test) {
4799+
const uint16_t from[11] = {0x0123, 0x1234, 0x2345, 0x3456, 0x4567, 0x5678,
4800+
0x6789, 0x789A, 0x89AB, 0x9ABC, 0xABCD};
4801+
uint16_t* to = new uint16_t[11];
4802+
to[10] = 0xFEFE;
4803+
typedef void (*TestRepMovsWords)(const uint16_t* from, uint16_t* to,
4804+
int count);
4805+
reinterpret_cast<TestRepMovsWords>(test->entry())(from, to, 10);
4806+
EXPECT_EQ(to[0], 0x0123u);
4807+
for (int i = 0; i < 10; i++) {
4808+
EXPECT_EQ(from[i], to[i]);
4809+
}
4810+
EXPECT_EQ(to[10], 0xFEFEu);
4811+
delete[] to;
4812+
EXPECT_DISASSEMBLY(
4813+
"push esi\n"
4814+
"push edi\n"
4815+
"push ecx\n"
4816+
"mov esi,[esp+0x10]\n"
4817+
"mov edi,[esp+0x14]\n"
4818+
"mov ecx,[esp+0x18]\n"
4819+
"rep movsw\n"
4820+
"pop ecx\n"
4821+
"pop edi\n"
4822+
"pop esi\n"
4823+
"ret\n");
4824+
}
4825+
4826+
ASSEMBLER_TEST_GENERATE(TestRepMovsDwords, assembler) {
4827+
// Preserve registers.
4828+
__ pushl(ESI);
4829+
__ pushl(EDI);
4830+
__ pushl(ECX);
4831+
__ movl(ESI, Address(ESP, 4 * target::kWordSize)); // from.
4832+
__ movl(EDI, Address(ESP, 5 * target::kWordSize)); // to.
4833+
__ movl(ECX, Address(ESP, 6 * target::kWordSize)); // count.
4834+
__ rep_movsl();
4835+
__ popl(ECX);
4836+
__ popl(EDI);
4837+
__ popl(ESI);
4838+
__ ret();
4839+
}
4840+
4841+
ASSEMBLER_TEST_RUN(TestRepMovsDwords, test) {
4842+
const uint32_t from[11] = {0x01234567, 0x12345678, 0x23456789, 0x3456789A,
4843+
0x456789AB, 0x56789ABC, 0x6789ABCD, 0x789ABCDE,
4844+
0x89ABCDEF, 0x9ABCDEF0, 0xABCDEF01};
4845+
uint32_t* to = new uint32_t[11];
4846+
to[10] = 0xFEFEFEFE;
4847+
typedef void (*TestRepMovsDwords)(const uint32_t* from, uint32_t* to,
4848+
int count);
4849+
reinterpret_cast<TestRepMovsDwords>(test->entry())(from, to, 10);
4850+
EXPECT_EQ(to[0], 0x01234567u);
4851+
for (int i = 0; i < 10; i++) {
4852+
EXPECT_EQ(from[i], to[i]);
4853+
}
4854+
EXPECT_EQ(to[10], 0xFEFEFEFEu);
4855+
delete[] to;
4856+
EXPECT_DISASSEMBLY(
4857+
"push esi\n"
4858+
"push edi\n"
4859+
"push ecx\n"
4860+
"mov esi,[esp+0x10]\n"
4861+
"mov edi,[esp+0x14]\n"
4862+
"mov ecx,[esp+0x18]\n"
4863+
"rep movsl\n"
4864+
"pop ecx\n"
4865+
"pop edi\n"
4866+
"pop esi\n"
4867+
"ret\n");
4868+
}
4869+
47814870
// Called from assembler_test.cc.
47824871
ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) {
47834872
__ pushl(THR);

runtime/vm/compiler/assembler/assembler_x64.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,11 +384,14 @@ void Assembler::movq(const Address& dst, const Immediate& imm) {
384384
}
385385
}
386386

387-
void Assembler::EmitSimple(int opcode, int opcode2) {
387+
void Assembler::EmitSimple(int opcode, int opcode2, int opcode3) {
388388
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
389389
EmitUint8(opcode);
390390
if (opcode2 != -1) {
391391
EmitUint8(opcode2);
392+
if (opcode3 != -1) {
393+
EmitUint8(opcode3);
394+
}
392395
}
393396
}
394397

runtime/vm/compiler/assembler/assembler_x64.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ class Assembler : public AssemblerBase {
391391
SIMPLE(fsin, 0xD9, 0xFE)
392392
SIMPLE(lock, 0xF0)
393393
SIMPLE(rep_movsb, 0xF3, 0xA4)
394+
SIMPLE(rep_movsw, 0xF3, 0x66, 0xA5)
395+
SIMPLE(rep_movsl, 0xF3, 0xA5)
396+
SIMPLE(rep_movsq, 0xF3, 0x48, 0xA5)
394397
#undef SIMPLE
395398
// XmmRegister operations with another register or an address.
396399
#define XX(width, name, ...) \
@@ -1030,7 +1033,7 @@ class Assembler : public AssemblerBase {
10301033
const Address& dst,
10311034
const Immediate& imm);
10321035

1033-
void EmitSimple(int opcode, int opcode2 = -1);
1036+
void EmitSimple(int opcode, int opcode2 = -1, int opcode3 = -1);
10341037
void EmitUnaryQ(Register reg, int opcode, int modrm_code);
10351038
void EmitUnaryL(Register reg, int opcode, int modrm_code);
10361039
void EmitUnaryQ(const Address& address, int opcode, int modrm_code);

runtime/vm/compiler/assembler/assembler_x64_test.cc

Lines changed: 162 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5556,14 +5556,16 @@ ASSEMBLER_TEST_GENERATE(TestRepMovsBytes, assembler) {
55565556
}
55575557

55585558
ASSEMBLER_TEST_RUN(TestRepMovsBytes, test) {
5559-
const char* from = "0123456789";
5560-
const char* to = new char[10];
5561-
typedef void (*TestRepMovsBytes)(const char* from, const char* to, int count);
5559+
const char* from = "0123456789x";
5560+
char* to = new char[11];
5561+
to[10] = 'y';
5562+
typedef void (*TestRepMovsBytes)(const char* from, char* to, int count);
55625563
reinterpret_cast<TestRepMovsBytes>(test->entry())(from, to, 10);
55635564
EXPECT_EQ(to[0], '0');
55645565
for (int i = 0; i < 10; i++) {
55655566
EXPECT_EQ(from[i], to[i]);
55665567
}
5568+
EXPECT_EQ(to[10], 'y');
55675569
delete[] to;
55685570
EXPECT_DISASSEMBLY_NOT_WINDOWS(
55695571
"push rsi\n"
@@ -5583,6 +5585,163 @@ ASSEMBLER_TEST_RUN(TestRepMovsBytes, test) {
55835585
"ret\n");
55845586
}
55855587

5588+
ASSEMBLER_TEST_GENERATE(TestRepMovsWords, assembler) {
5589+
__ pushq(RSI);
5590+
__ pushq(RDI);
5591+
__ pushq(CallingConventions::kArg1Reg); // from.
5592+
__ pushq(CallingConventions::kArg2Reg); // to.
5593+
__ pushq(CallingConventions::kArg3Reg); // count.
5594+
__ movq(RSI, Address(RSP, 2 * target::kWordSize)); // from.
5595+
__ movq(RDI, Address(RSP, 1 * target::kWordSize)); // to.
5596+
__ movq(RCX, Address(RSP, 0 * target::kWordSize)); // count.
5597+
__ rep_movsw();
5598+
// Remove saved arguments.
5599+
__ popq(RAX);
5600+
__ popq(RAX);
5601+
__ popq(RAX);
5602+
__ popq(RDI);
5603+
__ popq(RSI);
5604+
__ ret();
5605+
}
5606+
5607+
ASSEMBLER_TEST_RUN(TestRepMovsWords, test) {
5608+
const uint16_t from[11] = {0x0123, 0x1234, 0x2345, 0x3456, 0x4567, 0x5678,
5609+
0x6789, 0x789A, 0x89AB, 0x9ABC, 0xABCD};
5610+
uint16_t* to = new uint16_t[11];
5611+
to[10] = 0xFEFE;
5612+
typedef void (*TestRepMovsWords)(const uint16_t* from, uint16_t* to,
5613+
int count);
5614+
reinterpret_cast<TestRepMovsWords>(test->entry())(from, to, 10);
5615+
EXPECT_EQ(to[0], 0x0123u);
5616+
for (int i = 0; i < 10; i++) {
5617+
EXPECT_EQ(from[i], to[i]);
5618+
}
5619+
EXPECT_EQ(to[10], 0xFEFEu);
5620+
delete[] to;
5621+
EXPECT_DISASSEMBLY_NOT_WINDOWS(
5622+
"push rsi\n"
5623+
"push rdi\n"
5624+
"push rdi\n"
5625+
"push rsi\n"
5626+
"push rdx\n"
5627+
"movq rsi,[rsp+0x10]\n"
5628+
"movq rdi,[rsp+0x8]\n"
5629+
"movq rcx,[rsp]\n"
5630+
"rep movsw\n"
5631+
"pop rax\n"
5632+
"pop rax\n"
5633+
"pop rax\n"
5634+
"pop rdi\n"
5635+
"pop rsi\n"
5636+
"ret\n");
5637+
}
5638+
5639+
ASSEMBLER_TEST_GENERATE(TestRepMovsDwords, assembler) {
5640+
__ pushq(RSI);
5641+
__ pushq(RDI);
5642+
__ pushq(CallingConventions::kArg1Reg); // from.
5643+
__ pushq(CallingConventions::kArg2Reg); // to.
5644+
__ pushq(CallingConventions::kArg3Reg); // count.
5645+
__ movq(RSI, Address(RSP, 2 * target::kWordSize)); // from.
5646+
__ movq(RDI, Address(RSP, 1 * target::kWordSize)); // to.
5647+
__ movq(RCX, Address(RSP, 0 * target::kWordSize)); // count.
5648+
__ rep_movsl();
5649+
// Remove saved arguments.
5650+
__ popq(RAX);
5651+
__ popq(RAX);
5652+
__ popq(RAX);
5653+
__ popq(RDI);
5654+
__ popq(RSI);
5655+
__ ret();
5656+
}
5657+
5658+
ASSEMBLER_TEST_RUN(TestRepMovsDwords, test) {
5659+
const uint32_t from[11] = {0x01234567, 0x12345678, 0x23456789, 0x3456789A,
5660+
0x456789AB, 0x56789ABC, 0x6789ABCD, 0x789ABCDE,
5661+
0x89ABCDEF, 0x9ABCDEF0, 0xABCDEF01};
5662+
uint32_t* to = new uint32_t[11];
5663+
to[10] = 0xFEFEFEFE;
5664+
typedef void (*TestRepMovsDwords)(const uint32_t* from, uint32_t* to,
5665+
int count);
5666+
reinterpret_cast<TestRepMovsDwords>(test->entry())(from, to, 10);
5667+
EXPECT_EQ(to[0], 0x01234567u);
5668+
for (int i = 0; i < 10; i++) {
5669+
EXPECT_EQ(from[i], to[i]);
5670+
}
5671+
EXPECT_EQ(to[10], 0xFEFEFEFEu);
5672+
delete[] to;
5673+
EXPECT_DISASSEMBLY_NOT_WINDOWS(
5674+
"push rsi\n"
5675+
"push rdi\n"
5676+
"push rdi\n"
5677+
"push rsi\n"
5678+
"push rdx\n"
5679+
"movq rsi,[rsp+0x10]\n"
5680+
"movq rdi,[rsp+0x8]\n"
5681+
"movq rcx,[rsp]\n"
5682+
"rep movsl\n"
5683+
"pop rax\n"
5684+
"pop rax\n"
5685+
"pop rax\n"
5686+
"pop rdi\n"
5687+
"pop rsi\n"
5688+
"ret\n");
5689+
}
5690+
5691+
ASSEMBLER_TEST_GENERATE(TestRepMovsQwords, assembler) {
5692+
__ pushq(RSI);
5693+
__ pushq(RDI);
5694+
__ pushq(CallingConventions::kArg1Reg); // from.
5695+
__ pushq(CallingConventions::kArg2Reg); // to.
5696+
__ pushq(CallingConventions::kArg3Reg); // count.
5697+
__ movq(RSI, Address(RSP, 2 * target::kWordSize)); // from.
5698+
__ movq(RDI, Address(RSP, 1 * target::kWordSize)); // to.
5699+
__ movq(RCX, Address(RSP, 0 * target::kWordSize)); // count.
5700+
__ rep_movsq();
5701+
// Remove saved arguments.
5702+
__ popq(RAX);
5703+
__ popq(RAX);
5704+
__ popq(RAX);
5705+
__ popq(RDI);
5706+
__ popq(RSI);
5707+
__ ret();
5708+
}
5709+
5710+
ASSEMBLER_TEST_RUN(TestRepMovsQwords, test) {
5711+
const uint64_t from[11] = {
5712+
0x0123456789ABCDEF, 0x123456789ABCDEF0, 0x23456789ABCDEF01,
5713+
0x3456789ABCDEF012, 0x456789ABCDEF0123, 0x56789ABCDEF01234,
5714+
0x6789ABCDEF012345, 0x789ABCDEF0123456, 0x89ABCDEF01234567,
5715+
0x9ABCDEF012345678, 0xABCDEF0123456789};
5716+
uint64_t* to = new uint64_t[11];
5717+
to[10] = 0xFEFEFEFEFEFEFEFE;
5718+
typedef void (*TestRepMovsQwords)(const uint64_t* from, uint64_t* to,
5719+
int count);
5720+
reinterpret_cast<TestRepMovsQwords>(test->entry())(from, to, 10);
5721+
EXPECT_EQ(to[0], 0x0123456789ABCDEFu);
5722+
for (int i = 0; i < 10; i++) {
5723+
EXPECT_EQ(from[i], to[i]);
5724+
}
5725+
EXPECT_EQ(to[10], 0xFEFEFEFEFEFEFEFEu);
5726+
delete[] to;
5727+
EXPECT_DISASSEMBLY_NOT_WINDOWS(
5728+
"push rsi\n"
5729+
"push rdi\n"
5730+
"push rdi\n"
5731+
"push rsi\n"
5732+
"push rdx\n"
5733+
"movq rsi,[rsp+0x10]\n"
5734+
"movq rdi,[rsp+0x8]\n"
5735+
"movq rcx,[rsp]\n"
5736+
"rep movsq\n"
5737+
"pop rax\n"
5738+
"pop rax\n"
5739+
"pop rax\n"
5740+
"pop rdi\n"
5741+
"pop rsi\n"
5742+
"ret\n");
5743+
}
5744+
55865745
ASSEMBLER_TEST_GENERATE(ConditionalMovesCompare, assembler) {
55875746
__ cmpq(CallingConventions::kArg1Reg, CallingConventions::kArg2Reg);
55885747
__ movq(RDX, Immediate(1)); // Greater equal.

runtime/vm/compiler/assembler/disassembler_x86.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1150,7 +1150,25 @@ bool DisassemblerX64::DecodeInstructionType(uint8_t** data) {
11501150
// REP.
11511151
Print("rep ");
11521152
}
1153-
Print("%s", idesc.mnem);
1153+
if ((current & 0x01) == 0x01) {
1154+
// Operation size: word, dword or qword
1155+
switch (operand_size()) {
1156+
case WORD_SIZE:
1157+
Print("%sw", idesc.mnem);
1158+
break;
1159+
case DOUBLEWORD_SIZE:
1160+
Print("%sl", idesc.mnem);
1161+
break;
1162+
case QUADWORD_SIZE:
1163+
Print("%sq", idesc.mnem);
1164+
break;
1165+
default:
1166+
UNREACHABLE();
1167+
}
1168+
} else {
1169+
// Operation size: byte
1170+
Print("%s", idesc.mnem);
1171+
}
11541172
} else if (current == 0x99 && rex_w()) {
11551173
Print("cqo"); // Cdql is called cdq and cdqq is called cqo.
11561174
} else {

runtime/vm/compiler/backend/constant_propagator.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ void ConstantPropagator::VisitStoreIndexed(StoreIndexedInstr* instr) {}
298298
void ConstantPropagator::VisitStoreInstanceField(
299299
StoreInstanceFieldInstr* instr) {}
300300

301+
void ConstantPropagator::VisitMemoryCopy(MemoryCopyInstr* instr) {}
302+
301303
void ConstantPropagator::VisitDeoptimize(DeoptimizeInstr* instr) {
302304
// TODO(vegorov) remove all code after DeoptimizeInstr as dead.
303305
}

0 commit comments

Comments
 (0)