Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_MEMCOPY_H_
6 : #define V8_MEMCOPY_H_
7 :
8 : #include <stdint.h>
9 : #include <stdlib.h>
10 : #include <string.h>
11 :
12 : #include "src/base/logging.h"
13 : #include "src/base/macros.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : typedef uintptr_t Address;
19 :
20 : // ----------------------------------------------------------------------------
21 : // Generated memcpy/memmove for ia32, arm, and mips.
22 :
23 : void init_memcopy_functions();
24 :
25 : #if defined(V8_TARGET_ARCH_IA32)
26 : // Limit below which the extra overhead of the MemCopy function is likely
27 : // to outweigh the benefits of faster copying.
28 : const size_t kMinComplexMemCopy = 64;
29 :
30 : // Copy memory area. No restrictions.
31 : V8_EXPORT_PRIVATE void MemMove(void* dest, const void* src, size_t size);
32 : typedef void (*MemMoveFunction)(void* dest, const void* src, size_t size);
33 :
34 : // Keep the distinction of "move" vs. "copy" for the benefit of other
35 : // architectures.
36 : V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
37 : MemMove(dest, src, size);
38 : }
39 : #elif defined(V8_HOST_ARCH_ARM)
40 : typedef void (*MemCopyUint8Function)(uint8_t* dest, const uint8_t* src,
41 : size_t size);
42 : V8_EXPORT_PRIVATE extern MemCopyUint8Function memcopy_uint8_function;
43 : V8_INLINE void MemCopyUint8Wrapper(uint8_t* dest, const uint8_t* src,
44 : size_t chars) {
45 : memcpy(dest, src, chars);
46 : }
47 : // For values < 16, the assembler function is slower than the inlined C code.
48 : const size_t kMinComplexMemCopy = 16;
49 : V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
50 : (*memcopy_uint8_function)(reinterpret_cast<uint8_t*>(dest),
51 : reinterpret_cast<const uint8_t*>(src), size);
52 : }
53 : V8_EXPORT_PRIVATE V8_INLINE void MemMove(void* dest, const void* src,
54 : size_t size) {
55 : memmove(dest, src, size);
56 : }
57 :
58 : typedef void (*MemCopyUint16Uint8Function)(uint16_t* dest, const uint8_t* src,
59 : size_t size);
60 : extern MemCopyUint16Uint8Function memcopy_uint16_uint8_function;
61 : void MemCopyUint16Uint8Wrapper(uint16_t* dest, const uint8_t* src,
62 : size_t chars);
63 : // For values < 12, the assembler function is slower than the inlined C code.
64 : const int kMinComplexConvertMemCopy = 12;
65 : V8_INLINE void MemCopyUint16Uint8(uint16_t* dest, const uint8_t* src,
66 : size_t size) {
67 : (*memcopy_uint16_uint8_function)(dest, src, size);
68 : }
69 : #elif defined(V8_HOST_ARCH_MIPS)
70 : typedef void (*MemCopyUint8Function)(uint8_t* dest, const uint8_t* src,
71 : size_t size);
72 : V8_EXPORT_PRIVATE extern MemCopyUint8Function memcopy_uint8_function;
73 : V8_INLINE void MemCopyUint8Wrapper(uint8_t* dest, const uint8_t* src,
74 : size_t chars) {
75 : memcpy(dest, src, chars);
76 : }
77 : // For values < 16, the assembler function is slower than the inlined C code.
78 : const size_t kMinComplexMemCopy = 16;
79 : V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
80 : (*memcopy_uint8_function)(reinterpret_cast<uint8_t*>(dest),
81 : reinterpret_cast<const uint8_t*>(src), size);
82 : }
83 : V8_EXPORT_PRIVATE V8_INLINE void MemMove(void* dest, const void* src,
84 : size_t size) {
85 : memmove(dest, src, size);
86 : }
87 : #else
88 : // Copy memory area to disjoint memory area.
89 : V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
90 : memcpy(dest, src, size);
91 : }
92 : V8_EXPORT_PRIVATE V8_INLINE void MemMove(void* dest, const void* src,
93 : size_t size) {
94 : memmove(dest, src, size);
95 : }
96 : const size_t kMinComplexMemCopy = 8;
97 : #endif // V8_TARGET_ARCH_IA32
98 :
99 : // Copies words from |src| to |dst|. The data spans must not overlap.
100 : // |src| and |dst| must be TWord-size aligned.
101 : template <size_t kBlockCopyLimit, typename T>
102 181246743 : inline void CopyImpl(T* dst_ptr, const T* src_ptr, size_t count) {
103 : constexpr int kTWordSize = sizeof(T);
104 : #ifdef DEBUG
105 : Address dst = reinterpret_cast<Address>(dst_ptr);
106 : Address src = reinterpret_cast<Address>(src_ptr);
107 : DCHECK(IsAligned(dst, kTWordSize));
108 : DCHECK(IsAligned(src, kTWordSize));
109 : DCHECK(((src <= dst) && ((src + count * kTWordSize) <= dst)) ||
110 : ((dst <= src) && ((dst + count * kTWordSize) <= src)));
111 : #endif
112 :
113 : // Use block copying MemCopy if the segment we're copying is
114 : // enough to justify the extra call/setup overhead.
115 181246743 : if (count < kBlockCopyLimit) {
116 634068690 : do {
117 634068690 : count--;
118 634068690 : *dst_ptr++ = *src_ptr++;
119 : } while (count > 0);
120 : } else {
121 5170106 : MemCopy(dst_ptr, src_ptr, count * kTWordSize);
122 : }
123 181246743 : }
124 :
125 : // Copies kSystemPointerSize-sized words from |src| to |dst|. The data spans
126 : // must not overlap. |src| and |dst| must be kSystemPointerSize-aligned.
127 : inline void CopyWords(Address dst, const Address src, size_t num_words) {
128 : static const size_t kBlockCopyLimit = 16;
129 1133 : CopyImpl<kBlockCopyLimit>(reinterpret_cast<Address*>(dst),
130 1133 : reinterpret_cast<const Address*>(src), num_words);
131 : }
132 :
133 : // Copies data from |src| to |dst|. The data spans must not overlap.
134 : template <typename T>
135 : inline void CopyBytes(T* dst, const T* src, size_t num_bytes) {
136 : STATIC_ASSERT(sizeof(T) == 1);
137 5938291 : if (num_bytes == 0) return;
138 5614121 : CopyImpl<kMinComplexMemCopy>(dst, src, num_bytes);
139 : }
140 :
141 : inline void MemsetInt32(int32_t* dest, int32_t value, size_t counter) {
142 : #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
143 : #define STOS "stosl"
144 : #endif
145 :
146 : #if defined(MEMORY_SANITIZER)
147 : // MemorySanitizer does not understand inline assembly.
148 : #undef STOS
149 : #endif
150 :
151 : #if defined(__GNUC__) && defined(STOS)
152 : asm volatile(
153 : "cld;"
154 : "rep ; " STOS
155 : : "+&c"(counter), "+&D"(dest)
156 : : "a"(value)
157 : : "memory", "cc");
158 : #else
159 : for (size_t i = 0; i < counter; i++) {
160 : dest[i] = value;
161 : }
162 : #endif
163 :
164 : #undef STOS
165 : }
166 :
167 : inline void MemsetPointer(Address* dest, Address value, size_t counter) {
168 : #if V8_HOST_ARCH_IA32
169 : #define STOS "stosl"
170 : #elif V8_HOST_ARCH_X64
171 : #define STOS "stosq"
172 : #endif
173 :
174 : #if defined(MEMORY_SANITIZER)
175 : // MemorySanitizer does not understand inline assembly.
176 : #undef STOS
177 : #endif
178 :
179 : #if defined(__GNUC__) && defined(STOS)
180 : asm volatile(
181 : "cld;"
182 : "rep ; " STOS
183 : : "+&c"(counter), "+&D"(dest)
184 : : "a"(value)
185 62415235 : : "memory", "cc");
186 : #else
187 : for (size_t i = 0; i < counter; i++) {
188 : dest[i] = value;
189 : }
190 : #endif
191 :
192 : #undef STOS
193 : }
194 :
195 : template <typename T, typename U>
196 : inline void MemsetPointer(T** dest, U* value, size_t counter) {
197 : #ifdef DEBUG
198 : T* a = nullptr;
199 : U* b = nullptr;
200 : a = b; // Fake assignment to check assignability.
201 : USE(a);
202 : #endif // DEBUG
203 605298 : MemsetPointer(reinterpret_cast<Address*>(dest),
204 : reinterpret_cast<Address>(value), counter);
205 : }
206 :
207 : template <typename sourcechar, typename sinkchar>
208 : V8_INLINE static void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src,
209 : size_t chars);
210 : #if defined(V8_HOST_ARCH_ARM)
211 : V8_INLINE void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src,
212 : size_t chars);
213 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src,
214 : size_t chars);
215 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src,
216 : size_t chars);
217 : #elif defined(V8_HOST_ARCH_MIPS)
218 : V8_INLINE void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src,
219 : size_t chars);
220 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src,
221 : size_t chars);
222 : #elif defined(V8_HOST_ARCH_PPC) || defined(V8_HOST_ARCH_S390)
223 : V8_INLINE void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src,
224 : size_t chars);
225 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src,
226 : size_t chars);
227 : #endif
228 :
229 : // Copy from 8bit/16bit chars to 8bit/16bit chars.
230 : template <typename sourcechar, typename sinkchar>
231 : V8_INLINE void CopyChars(sinkchar* dest, const sourcechar* src, size_t chars);
232 :
233 : template <typename sourcechar, typename sinkchar>
234 : void CopyChars(sinkchar* dest, const sourcechar* src, size_t chars) {
235 : DCHECK_LE(sizeof(sourcechar), 2);
236 : DCHECK_LE(sizeof(sinkchar), 2);
237 : if (sizeof(sinkchar) == 1) {
238 : if (sizeof(sourcechar) == 1) {
239 : CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
240 : reinterpret_cast<const uint8_t*>(src), chars);
241 : } else {
242 : CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
243 : reinterpret_cast<const uint16_t*>(src), chars);
244 : }
245 : } else {
246 : if (sizeof(sourcechar) == 1) {
247 : CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
248 : reinterpret_cast<const uint8_t*>(src), chars);
249 : } else {
250 : CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
251 : reinterpret_cast<const uint16_t*>(src), chars);
252 : }
253 : }
254 : }
255 :
256 : template <typename sourcechar, typename sinkchar>
257 : void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src, size_t chars) {
258 248458740 : sinkchar* limit = dest + chars;
259 221308071 : if ((sizeof(*dest) == sizeof(*src)) &&
260 : (chars >= kMinComplexMemCopy / sizeof(*dest))) {
261 : MemCopy(dest, src, chars * sizeof(*dest));
262 : } else {
263 5562021704 : while (dest < limit) *dest++ = static_cast<sinkchar>(*src++);
264 : }
265 : }
266 :
267 : #if defined(V8_HOST_ARCH_ARM)
268 : void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) {
269 : switch (static_cast<unsigned>(chars)) {
270 : case 0:
271 : break;
272 : case 1:
273 : *dest = *src;
274 : break;
275 : case 2:
276 : memcpy(dest, src, 2);
277 : break;
278 : case 3:
279 : memcpy(dest, src, 3);
280 : break;
281 : case 4:
282 : memcpy(dest, src, 4);
283 : break;
284 : case 5:
285 : memcpy(dest, src, 5);
286 : break;
287 : case 6:
288 : memcpy(dest, src, 6);
289 : break;
290 : case 7:
291 : memcpy(dest, src, 7);
292 : break;
293 : case 8:
294 : memcpy(dest, src, 8);
295 : break;
296 : case 9:
297 : memcpy(dest, src, 9);
298 : break;
299 : case 10:
300 : memcpy(dest, src, 10);
301 : break;
302 : case 11:
303 : memcpy(dest, src, 11);
304 : break;
305 : case 12:
306 : memcpy(dest, src, 12);
307 : break;
308 : case 13:
309 : memcpy(dest, src, 13);
310 : break;
311 : case 14:
312 : memcpy(dest, src, 14);
313 : break;
314 : case 15:
315 : memcpy(dest, src, 15);
316 : break;
317 : default:
318 : MemCopy(dest, src, chars);
319 : break;
320 : }
321 : }
322 :
323 : void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src, size_t chars) {
324 : if (chars >= static_cast<size_t>(kMinComplexConvertMemCopy)) {
325 : MemCopyUint16Uint8(dest, src, chars);
326 : } else {
327 : MemCopyUint16Uint8Wrapper(dest, src, chars);
328 : }
329 : }
330 :
331 : void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) {
332 : switch (static_cast<unsigned>(chars)) {
333 : case 0:
334 : break;
335 : case 1:
336 : *dest = *src;
337 : break;
338 : case 2:
339 : memcpy(dest, src, 4);
340 : break;
341 : case 3:
342 : memcpy(dest, src, 6);
343 : break;
344 : case 4:
345 : memcpy(dest, src, 8);
346 : break;
347 : case 5:
348 : memcpy(dest, src, 10);
349 : break;
350 : case 6:
351 : memcpy(dest, src, 12);
352 : break;
353 : case 7:
354 : memcpy(dest, src, 14);
355 : break;
356 : default:
357 : MemCopy(dest, src, chars * sizeof(*dest));
358 : break;
359 : }
360 : }
361 :
362 : #elif defined(V8_HOST_ARCH_MIPS)
363 : void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) {
364 : if (chars < kMinComplexMemCopy) {
365 : memcpy(dest, src, chars);
366 : } else {
367 : MemCopy(dest, src, chars);
368 : }
369 : }
370 :
371 : void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) {
372 : if (chars < kMinComplexMemCopy) {
373 : memcpy(dest, src, chars * sizeof(*dest));
374 : } else {
375 : MemCopy(dest, src, chars * sizeof(*dest));
376 : }
377 : }
378 : #elif defined(V8_HOST_ARCH_PPC) || defined(V8_HOST_ARCH_S390)
379 : #define CASE(n) \
380 : case n: \
381 : memcpy(dest, src, n); \
382 : break
383 : void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) {
384 : switch (static_cast<unsigned>(chars)) {
385 : case 0:
386 : break;
387 : case 1:
388 : *dest = *src;
389 : break;
390 : CASE(2);
391 : CASE(3);
392 : CASE(4);
393 : CASE(5);
394 : CASE(6);
395 : CASE(7);
396 : CASE(8);
397 : CASE(9);
398 : CASE(10);
399 : CASE(11);
400 : CASE(12);
401 : CASE(13);
402 : CASE(14);
403 : CASE(15);
404 : CASE(16);
405 : CASE(17);
406 : CASE(18);
407 : CASE(19);
408 : CASE(20);
409 : CASE(21);
410 : CASE(22);
411 : CASE(23);
412 : CASE(24);
413 : CASE(25);
414 : CASE(26);
415 : CASE(27);
416 : CASE(28);
417 : CASE(29);
418 : CASE(30);
419 : CASE(31);
420 : CASE(32);
421 : CASE(33);
422 : CASE(34);
423 : CASE(35);
424 : CASE(36);
425 : CASE(37);
426 : CASE(38);
427 : CASE(39);
428 : CASE(40);
429 : CASE(41);
430 : CASE(42);
431 : CASE(43);
432 : CASE(44);
433 : CASE(45);
434 : CASE(46);
435 : CASE(47);
436 : CASE(48);
437 : CASE(49);
438 : CASE(50);
439 : CASE(51);
440 : CASE(52);
441 : CASE(53);
442 : CASE(54);
443 : CASE(55);
444 : CASE(56);
445 : CASE(57);
446 : CASE(58);
447 : CASE(59);
448 : CASE(60);
449 : CASE(61);
450 : CASE(62);
451 : CASE(63);
452 : CASE(64);
453 : default:
454 : memcpy(dest, src, chars);
455 : break;
456 : }
457 : }
458 : #undef CASE
459 :
460 : #define CASE(n) \
461 : case n: \
462 : memcpy(dest, src, n * 2); \
463 : break
464 : void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) {
465 : switch (static_cast<unsigned>(chars)) {
466 : case 0:
467 : break;
468 : case 1:
469 : *dest = *src;
470 : break;
471 : CASE(2);
472 : CASE(3);
473 : CASE(4);
474 : CASE(5);
475 : CASE(6);
476 : CASE(7);
477 : CASE(8);
478 : CASE(9);
479 : CASE(10);
480 : CASE(11);
481 : CASE(12);
482 : CASE(13);
483 : CASE(14);
484 : CASE(15);
485 : CASE(16);
486 : CASE(17);
487 : CASE(18);
488 : CASE(19);
489 : CASE(20);
490 : CASE(21);
491 : CASE(22);
492 : CASE(23);
493 : CASE(24);
494 : CASE(25);
495 : CASE(26);
496 : CASE(27);
497 : CASE(28);
498 : CASE(29);
499 : CASE(30);
500 : CASE(31);
501 : CASE(32);
502 : default:
503 : memcpy(dest, src, chars * 2);
504 : break;
505 : }
506 : }
507 : #undef CASE
508 : #endif
509 :
510 : } // namespace internal
511 : } // namespace v8
512 :
513 : #endif // V8_MEMCOPY_H_
|