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 int 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 int 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 int 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 int 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 kSystemPointerSize-aligned.
101 186841442 : inline void CopyWords(Address dst, const Address src, size_t num_words) {
102 : constexpr int kSystemPointerSize = sizeof(void*); // to avoid src/globals.h
103 : DCHECK(IsAligned(dst, kSystemPointerSize));
104 : DCHECK(IsAligned(src, kSystemPointerSize));
105 : DCHECK(((src <= dst) && ((src + num_words * kSystemPointerSize) <= dst)) ||
106 : ((dst <= src) && ((dst + num_words * kSystemPointerSize) <= src)));
107 :
108 : // Use block copying MemCopy if the segment we're copying is
109 : // enough to justify the extra call/setup overhead.
110 : static const size_t kBlockCopyLimit = 16;
111 :
112 186841442 : Address* dst_ptr = reinterpret_cast<Address*>(dst);
113 186841442 : Address* src_ptr = reinterpret_cast<Address*>(src);
114 186841442 : if (num_words < kBlockCopyLimit) {
115 694766859 : do {
116 694766859 : num_words--;
117 694766859 : *dst_ptr++ = *src_ptr++;
118 : } while (num_words > 0);
119 : } else {
120 5194308 : MemCopy(dst_ptr, src_ptr, num_words * kSystemPointerSize);
121 : }
122 186841442 : }
123 :
124 : // Copies data from |src| to |dst|. The data spans must not overlap.
125 : template <typename T>
126 6520165 : inline void CopyBytes(T* dst, const T* src, size_t num_bytes) {
127 : STATIC_ASSERT(sizeof(T) == 1);
128 : DCHECK(((src <= dst) && ((src + num_bytes) <= dst)) ||
129 : ((dst <= src) && ((dst + num_bytes) <= src)));
130 13040330 : if (num_bytes == 0) return;
131 :
132 : // Use block copying MemCopy if the segment we're copying is
133 : // enough to justify the extra call/setup overhead.
134 : static const int kBlockCopyLimit = kMinComplexMemCopy;
135 :
136 6146672 : if (num_bytes < static_cast<size_t>(kBlockCopyLimit)) {
137 4727663 : do {
138 4727663 : num_bytes--;
139 4727663 : *dst++ = *src++;
140 : } while (num_bytes > 0);
141 : } else {
142 : MemCopy(dst, src, num_bytes);
143 : }
144 : }
145 :
146 : inline void MemsetPointer(Address* dest, Address value, size_t counter) {
147 : #if V8_HOST_ARCH_IA32
148 : #define STOS "stosl"
149 : #elif V8_HOST_ARCH_X64
150 : #define STOS "stosq"
151 : #endif
152 :
153 : #if defined(MEMORY_SANITIZER)
154 : // MemorySanitizer does not understand inline assembly.
155 : #undef STOS
156 : #endif
157 :
158 : #if defined(__GNUC__) && defined(STOS)
159 : asm volatile(
160 : "cld;"
161 : "rep ; " STOS
162 : : "+&c"(counter), "+&D"(dest)
163 : : "a"(value)
164 54524471 : : "memory", "cc");
165 : #else
166 : for (size_t i = 0; i < counter; i++) {
167 : dest[i] = value;
168 : }
169 : #endif
170 :
171 : #undef STOS
172 : }
173 :
174 : template <typename T, typename U>
175 : inline void MemsetPointer(T** dest, U* value, size_t counter) {
176 : #ifdef DEBUG
177 : T* a = nullptr;
178 : U* b = nullptr;
179 : a = b; // Fake assignment to check assignability.
180 : USE(a);
181 : #endif // DEBUG
182 : MemsetPointer(reinterpret_cast<Address*>(dest),
183 609977 : reinterpret_cast<Address>(value), counter);
184 : }
185 :
186 : template <typename sourcechar, typename sinkchar>
187 : V8_INLINE static void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src,
188 : size_t chars);
189 : #if defined(V8_HOST_ARCH_ARM)
190 : V8_INLINE void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src,
191 : size_t chars);
192 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src,
193 : size_t chars);
194 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src,
195 : size_t chars);
196 : #elif defined(V8_HOST_ARCH_MIPS)
197 : V8_INLINE void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src,
198 : size_t chars);
199 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src,
200 : size_t chars);
201 : #elif defined(V8_HOST_ARCH_PPC) || defined(V8_HOST_ARCH_S390)
202 : V8_INLINE void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src,
203 : size_t chars);
204 : V8_INLINE void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src,
205 : size_t chars);
206 : #endif
207 :
208 : // Copy from 8bit/16bit chars to 8bit/16bit chars.
209 : template <typename sourcechar, typename sinkchar>
210 : V8_INLINE void CopyChars(sinkchar* dest, const sourcechar* src, size_t chars);
211 :
212 : template <typename sourcechar, typename sinkchar>
213 : void CopyChars(sinkchar* dest, const sourcechar* src, size_t chars) {
214 : DCHECK_LE(sizeof(sourcechar), 2);
215 : DCHECK_LE(sizeof(sinkchar), 2);
216 : if (sizeof(sinkchar) == 1) {
217 : if (sizeof(sourcechar) == 1) {
218 : CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
219 : reinterpret_cast<const uint8_t*>(src), chars);
220 : } else {
221 : CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
222 : reinterpret_cast<const uint16_t*>(src), chars);
223 : }
224 : } else {
225 : if (sizeof(sourcechar) == 1) {
226 : CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
227 : reinterpret_cast<const uint8_t*>(src), chars);
228 : } else {
229 : CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
230 : reinterpret_cast<const uint16_t*>(src), chars);
231 : }
232 : }
233 : }
234 :
235 : template <typename sourcechar, typename sinkchar>
236 : void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src, size_t chars) {
237 238218213 : sinkchar* limit = dest + chars;
238 211379325 : if ((sizeof(*dest) == sizeof(*src)) &&
239 : (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest)))) {
240 : MemCopy(dest, src, chars * sizeof(*dest));
241 : } else {
242 5231973332 : while (dest < limit) *dest++ = static_cast<sinkchar>(*src++);
243 : }
244 : }
245 :
246 : #if defined(V8_HOST_ARCH_ARM)
247 : void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) {
248 : switch (static_cast<unsigned>(chars)) {
249 : case 0:
250 : break;
251 : case 1:
252 : *dest = *src;
253 : break;
254 : case 2:
255 : memcpy(dest, src, 2);
256 : break;
257 : case 3:
258 : memcpy(dest, src, 3);
259 : break;
260 : case 4:
261 : memcpy(dest, src, 4);
262 : break;
263 : case 5:
264 : memcpy(dest, src, 5);
265 : break;
266 : case 6:
267 : memcpy(dest, src, 6);
268 : break;
269 : case 7:
270 : memcpy(dest, src, 7);
271 : break;
272 : case 8:
273 : memcpy(dest, src, 8);
274 : break;
275 : case 9:
276 : memcpy(dest, src, 9);
277 : break;
278 : case 10:
279 : memcpy(dest, src, 10);
280 : break;
281 : case 11:
282 : memcpy(dest, src, 11);
283 : break;
284 : case 12:
285 : memcpy(dest, src, 12);
286 : break;
287 : case 13:
288 : memcpy(dest, src, 13);
289 : break;
290 : case 14:
291 : memcpy(dest, src, 14);
292 : break;
293 : case 15:
294 : memcpy(dest, src, 15);
295 : break;
296 : default:
297 : MemCopy(dest, src, chars);
298 : break;
299 : }
300 : }
301 :
302 : void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src, size_t chars) {
303 : if (chars >= static_cast<size_t>(kMinComplexConvertMemCopy)) {
304 : MemCopyUint16Uint8(dest, src, chars);
305 : } else {
306 : MemCopyUint16Uint8Wrapper(dest, src, chars);
307 : }
308 : }
309 :
310 : void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) {
311 : switch (static_cast<unsigned>(chars)) {
312 : case 0:
313 : break;
314 : case 1:
315 : *dest = *src;
316 : break;
317 : case 2:
318 : memcpy(dest, src, 4);
319 : break;
320 : case 3:
321 : memcpy(dest, src, 6);
322 : break;
323 : case 4:
324 : memcpy(dest, src, 8);
325 : break;
326 : case 5:
327 : memcpy(dest, src, 10);
328 : break;
329 : case 6:
330 : memcpy(dest, src, 12);
331 : break;
332 : case 7:
333 : memcpy(dest, src, 14);
334 : break;
335 : default:
336 : MemCopy(dest, src, chars * sizeof(*dest));
337 : break;
338 : }
339 : }
340 :
341 : #elif defined(V8_HOST_ARCH_MIPS)
342 : void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) {
343 : if (chars < kMinComplexMemCopy) {
344 : memcpy(dest, src, chars);
345 : } else {
346 : MemCopy(dest, src, chars);
347 : }
348 : }
349 :
350 : void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) {
351 : if (chars < kMinComplexMemCopy) {
352 : memcpy(dest, src, chars * sizeof(*dest));
353 : } else {
354 : MemCopy(dest, src, chars * sizeof(*dest));
355 : }
356 : }
357 : #elif defined(V8_HOST_ARCH_PPC) || defined(V8_HOST_ARCH_S390)
358 : #define CASE(n) \
359 : case n: \
360 : memcpy(dest, src, n); \
361 : break
362 : void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) {
363 : switch (static_cast<unsigned>(chars)) {
364 : case 0:
365 : break;
366 : case 1:
367 : *dest = *src;
368 : break;
369 : CASE(2);
370 : CASE(3);
371 : CASE(4);
372 : CASE(5);
373 : CASE(6);
374 : CASE(7);
375 : CASE(8);
376 : CASE(9);
377 : CASE(10);
378 : CASE(11);
379 : CASE(12);
380 : CASE(13);
381 : CASE(14);
382 : CASE(15);
383 : CASE(16);
384 : CASE(17);
385 : CASE(18);
386 : CASE(19);
387 : CASE(20);
388 : CASE(21);
389 : CASE(22);
390 : CASE(23);
391 : CASE(24);
392 : CASE(25);
393 : CASE(26);
394 : CASE(27);
395 : CASE(28);
396 : CASE(29);
397 : CASE(30);
398 : CASE(31);
399 : CASE(32);
400 : CASE(33);
401 : CASE(34);
402 : CASE(35);
403 : CASE(36);
404 : CASE(37);
405 : CASE(38);
406 : CASE(39);
407 : CASE(40);
408 : CASE(41);
409 : CASE(42);
410 : CASE(43);
411 : CASE(44);
412 : CASE(45);
413 : CASE(46);
414 : CASE(47);
415 : CASE(48);
416 : CASE(49);
417 : CASE(50);
418 : CASE(51);
419 : CASE(52);
420 : CASE(53);
421 : CASE(54);
422 : CASE(55);
423 : CASE(56);
424 : CASE(57);
425 : CASE(58);
426 : CASE(59);
427 : CASE(60);
428 : CASE(61);
429 : CASE(62);
430 : CASE(63);
431 : CASE(64);
432 : default:
433 : memcpy(dest, src, chars);
434 : break;
435 : }
436 : }
437 : #undef CASE
438 :
439 : #define CASE(n) \
440 : case n: \
441 : memcpy(dest, src, n * 2); \
442 : break
443 : void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) {
444 : switch (static_cast<unsigned>(chars)) {
445 : case 0:
446 : break;
447 : case 1:
448 : *dest = *src;
449 : break;
450 : CASE(2);
451 : CASE(3);
452 : CASE(4);
453 : CASE(5);
454 : CASE(6);
455 : CASE(7);
456 : CASE(8);
457 : CASE(9);
458 : CASE(10);
459 : CASE(11);
460 : CASE(12);
461 : CASE(13);
462 : CASE(14);
463 : CASE(15);
464 : CASE(16);
465 : CASE(17);
466 : CASE(18);
467 : CASE(19);
468 : CASE(20);
469 : CASE(21);
470 : CASE(22);
471 : CASE(23);
472 : CASE(24);
473 : CASE(25);
474 : CASE(26);
475 : CASE(27);
476 : CASE(28);
477 : CASE(29);
478 : CASE(30);
479 : CASE(31);
480 : CASE(32);
481 : default:
482 : memcpy(dest, src, chars * 2);
483 : break;
484 : }
485 : }
486 : #undef CASE
487 : #endif
488 :
489 : } // namespace internal
490 : } // namespace v8
491 :
492 : #endif // V8_MEMCOPY_H_
|