• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #if defined(V8_TARGET_ARCH_IA32)
31 
32 #include "codegen.h"
33 
34 namespace v8 {
35 namespace internal {
36 
37 
38 // -------------------------------------------------------------------------
39 // Platform-specific RuntimeCallHelper functions.
40 
BeforeCall(MacroAssembler * masm) const41 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
42   masm->EnterInternalFrame();
43 }
44 
45 
AfterCall(MacroAssembler * masm) const46 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
47   masm->LeaveInternalFrame();
48 }
49 
50 
51 #define __ masm.
52 
MemCopyWrapper(void * dest,const void * src,size_t size)53 static void MemCopyWrapper(void* dest, const void* src, size_t size) {
54   memcpy(dest, src, size);
55 }
56 
57 
CreateMemCopyFunction()58 OS::MemCopyFunction CreateMemCopyFunction() {
59   size_t actual_size;
60   // Allocate buffer in executable space.
61   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
62                                                  &actual_size,
63                                                  true));
64   if (buffer == NULL) return &MemCopyWrapper;
65   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
66 
67   // Generated code is put into a fixed, unmovable, buffer, and not into
68   // the V8 heap. We can't, and don't, refer to any relocatable addresses
69   // (e.g. the JavaScript nan-object).
70 
71   // 32-bit C declaration function calls pass arguments on stack.
72 
73   // Stack layout:
74   // esp[12]: Third argument, size.
75   // esp[8]: Second argument, source pointer.
76   // esp[4]: First argument, destination pointer.
77   // esp[0]: return address
78 
79   const int kDestinationOffset = 1 * kPointerSize;
80   const int kSourceOffset = 2 * kPointerSize;
81   const int kSizeOffset = 3 * kPointerSize;
82 
83   int stack_offset = 0;  // Update if we change the stack height.
84 
85   if (FLAG_debug_code) {
86     __ cmp(Operand(esp, kSizeOffset + stack_offset),
87            Immediate(OS::kMinComplexMemCopy));
88     Label ok;
89     __ j(greater_equal, &ok);
90     __ int3();
91     __ bind(&ok);
92   }
93   if (CpuFeatures::IsSupported(SSE2)) {
94     CpuFeatures::Scope enable(SSE2);
95     __ push(edi);
96     __ push(esi);
97     stack_offset += 2 * kPointerSize;
98     Register dst = edi;
99     Register src = esi;
100     Register count = ecx;
101     __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
102     __ mov(src, Operand(esp, stack_offset + kSourceOffset));
103     __ mov(count, Operand(esp, stack_offset + kSizeOffset));
104 
105 
106     __ movdqu(xmm0, Operand(src, 0));
107     __ movdqu(Operand(dst, 0), xmm0);
108     __ mov(edx, dst);
109     __ and_(edx, 0xF);
110     __ neg(edx);
111     __ add(Operand(edx), Immediate(16));
112     __ add(dst, Operand(edx));
113     __ add(src, Operand(edx));
114     __ sub(Operand(count), edx);
115 
116     // edi is now aligned. Check if esi is also aligned.
117     Label unaligned_source;
118     __ test(Operand(src), Immediate(0x0F));
119     __ j(not_zero, &unaligned_source);
120     {
121       // Copy loop for aligned source and destination.
122       __ mov(edx, count);
123       Register loop_count = ecx;
124       Register count = edx;
125       __ shr(loop_count, 5);
126       {
127         // Main copy loop.
128         Label loop;
129         __ bind(&loop);
130         __ prefetch(Operand(src, 0x20), 1);
131         __ movdqa(xmm0, Operand(src, 0x00));
132         __ movdqa(xmm1, Operand(src, 0x10));
133         __ add(Operand(src), Immediate(0x20));
134 
135         __ movdqa(Operand(dst, 0x00), xmm0);
136         __ movdqa(Operand(dst, 0x10), xmm1);
137         __ add(Operand(dst), Immediate(0x20));
138 
139         __ dec(loop_count);
140         __ j(not_zero, &loop);
141       }
142 
143       // At most 31 bytes to copy.
144       Label move_less_16;
145       __ test(Operand(count), Immediate(0x10));
146       __ j(zero, &move_less_16);
147       __ movdqa(xmm0, Operand(src, 0));
148       __ add(Operand(src), Immediate(0x10));
149       __ movdqa(Operand(dst, 0), xmm0);
150       __ add(Operand(dst), Immediate(0x10));
151       __ bind(&move_less_16);
152 
153       // At most 15 bytes to copy. Copy 16 bytes at end of string.
154       __ and_(count, 0xF);
155       __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
156       __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
157 
158       __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
159       __ pop(esi);
160       __ pop(edi);
161       __ ret(0);
162     }
163     __ Align(16);
164     {
165       // Copy loop for unaligned source and aligned destination.
166       // If source is not aligned, we can't read it as efficiently.
167       __ bind(&unaligned_source);
168       __ mov(edx, ecx);
169       Register loop_count = ecx;
170       Register count = edx;
171       __ shr(loop_count, 5);
172       {
173         // Main copy loop
174         Label loop;
175         __ bind(&loop);
176         __ prefetch(Operand(src, 0x20), 1);
177         __ movdqu(xmm0, Operand(src, 0x00));
178         __ movdqu(xmm1, Operand(src, 0x10));
179         __ add(Operand(src), Immediate(0x20));
180 
181         __ movdqa(Operand(dst, 0x00), xmm0);
182         __ movdqa(Operand(dst, 0x10), xmm1);
183         __ add(Operand(dst), Immediate(0x20));
184 
185         __ dec(loop_count);
186         __ j(not_zero, &loop);
187       }
188 
189       // At most 31 bytes to copy.
190       Label move_less_16;
191       __ test(Operand(count), Immediate(0x10));
192       __ j(zero, &move_less_16);
193       __ movdqu(xmm0, Operand(src, 0));
194       __ add(Operand(src), Immediate(0x10));
195       __ movdqa(Operand(dst, 0), xmm0);
196       __ add(Operand(dst), Immediate(0x10));
197       __ bind(&move_less_16);
198 
199       // At most 15 bytes to copy. Copy 16 bytes at end of string.
200       __ and_(count, 0x0F);
201       __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
202       __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
203 
204       __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
205       __ pop(esi);
206       __ pop(edi);
207       __ ret(0);
208     }
209 
210   } else {
211     // SSE2 not supported. Unlikely to happen in practice.
212     __ push(edi);
213     __ push(esi);
214     stack_offset += 2 * kPointerSize;
215     __ cld();
216     Register dst = edi;
217     Register src = esi;
218     Register count = ecx;
219     __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
220     __ mov(src, Operand(esp, stack_offset + kSourceOffset));
221     __ mov(count, Operand(esp, stack_offset + kSizeOffset));
222 
223     // Copy the first word.
224     __ mov(eax, Operand(src, 0));
225     __ mov(Operand(dst, 0), eax);
226 
227     // Increment src,dstso that dst is aligned.
228     __ mov(edx, dst);
229     __ and_(edx, 0x03);
230     __ neg(edx);
231     __ add(Operand(edx), Immediate(4));  // edx = 4 - (dst & 3)
232     __ add(dst, Operand(edx));
233     __ add(src, Operand(edx));
234     __ sub(Operand(count), edx);
235     // edi is now aligned, ecx holds number of remaning bytes to copy.
236 
237     __ mov(edx, count);
238     count = edx;
239     __ shr(ecx, 2);  // Make word count instead of byte count.
240     __ rep_movs();
241 
242     // At most 3 bytes left to copy. Copy 4 bytes at end of string.
243     __ and_(count, 3);
244     __ mov(eax, Operand(src, count, times_1, -4));
245     __ mov(Operand(dst, count, times_1, -4), eax);
246 
247     __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
248     __ pop(esi);
249     __ pop(edi);
250     __ ret(0);
251   }
252 
253   CodeDesc desc;
254   masm.GetCode(&desc);
255   ASSERT(desc.reloc_size == 0);
256 
257   CPU::FlushICache(buffer, actual_size);
258   return FUNCTION_CAST<OS::MemCopyFunction>(buffer);
259 }
260 
261 #undef __
262 
263 } }  // namespace v8::internal
264 
265 #endif  // V8_TARGET_ARCH_IA32
266