The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / deps / v8 / src / ia32 / codegen-ia32.cc @ f230a1cf
History | View | Annotate | Download (39.6 KB)
1 |
// Copyright 2012 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 V8_TARGET_ARCH_IA32
|
31 |
|
32 |
#include "codegen.h" |
33 |
#include "heap.h" |
34 |
#include "macro-assembler.h" |
35 |
|
36 |
namespace v8 {
|
37 |
namespace internal {
|
38 |
|
39 |
|
40 |
// -------------------------------------------------------------------------
|
41 |
// Platform-specific RuntimeCallHelper functions.
|
42 |
|
43 |
void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
44 |
masm->EnterFrame(StackFrame::INTERNAL); |
45 |
ASSERT(!masm->has_frame()); |
46 |
masm->set_has_frame(true);
|
47 |
} |
48 |
|
49 |
|
50 |
void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
51 |
masm->LeaveFrame(StackFrame::INTERNAL); |
52 |
ASSERT(masm->has_frame()); |
53 |
masm->set_has_frame(false);
|
54 |
} |
55 |
|
56 |
|
57 |
#define __ masm.
|
58 |
|
59 |
|
60 |
UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { |
61 |
size_t actual_size; |
62 |
// Allocate buffer in executable space.
|
63 |
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, |
64 |
&actual_size, |
65 |
true));
|
66 |
if (buffer == NULL) { |
67 |
// Fallback to library function if function cannot be created.
|
68 |
switch (type) {
|
69 |
case TranscendentalCache::SIN: return &sin; |
70 |
case TranscendentalCache::COS: return &cos; |
71 |
case TranscendentalCache::TAN: return &tan; |
72 |
case TranscendentalCache::LOG: return &log; |
73 |
default: UNIMPLEMENTED();
|
74 |
} |
75 |
} |
76 |
|
77 |
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); |
78 |
// esp[1 * kPointerSize]: raw double input
|
79 |
// esp[0 * kPointerSize]: return address
|
80 |
// Move double input into registers.
|
81 |
|
82 |
__ push(ebx); |
83 |
__ push(edx); |
84 |
__ push(edi); |
85 |
__ fld_d(Operand(esp, 4 * kPointerSize));
|
86 |
__ mov(ebx, Operand(esp, 4 * kPointerSize));
|
87 |
__ mov(edx, Operand(esp, 5 * kPointerSize));
|
88 |
TranscendentalCacheStub::GenerateOperation(&masm, type); |
89 |
// The return value is expected to be on ST(0) of the FPU stack.
|
90 |
__ pop(edi); |
91 |
__ pop(edx); |
92 |
__ pop(ebx); |
93 |
__ Ret(); |
94 |
|
95 |
CodeDesc desc; |
96 |
masm.GetCode(&desc); |
97 |
ASSERT(!RelocInfo::RequiresRelocation(desc)); |
98 |
|
99 |
CPU::FlushICache(buffer, actual_size); |
100 |
OS::ProtectCode(buffer, actual_size); |
101 |
return FUNCTION_CAST<UnaryMathFunction>(buffer);
|
102 |
} |
103 |
|
104 |
|
105 |
UnaryMathFunction CreateExpFunction() { |
106 |
if (!CpuFeatures::IsSupported(SSE2)) return &exp; |
107 |
if (!FLAG_fast_math) return &exp; |
108 |
size_t actual_size; |
109 |
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); |
110 |
if (buffer == NULL) return &exp; |
111 |
ExternalReference::InitializeMathExpData(); |
112 |
|
113 |
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); |
114 |
// esp[1 * kPointerSize]: raw double input
|
115 |
// esp[0 * kPointerSize]: return address
|
116 |
{ |
117 |
CpuFeatureScope use_sse2(&masm, SSE2); |
118 |
XMMRegister input = xmm1; |
119 |
XMMRegister result = xmm2; |
120 |
__ movsd(input, Operand(esp, 1 * kPointerSize));
|
121 |
__ push(eax); |
122 |
__ push(ebx); |
123 |
|
124 |
MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx); |
125 |
|
126 |
__ pop(ebx); |
127 |
__ pop(eax); |
128 |
__ movsd(Operand(esp, 1 * kPointerSize), result);
|
129 |
__ fld_d(Operand(esp, 1 * kPointerSize));
|
130 |
__ Ret(); |
131 |
} |
132 |
|
133 |
CodeDesc desc; |
134 |
masm.GetCode(&desc); |
135 |
ASSERT(!RelocInfo::RequiresRelocation(desc)); |
136 |
|
137 |
CPU::FlushICache(buffer, actual_size); |
138 |
OS::ProtectCode(buffer, actual_size); |
139 |
return FUNCTION_CAST<UnaryMathFunction>(buffer);
|
140 |
} |
141 |
|
142 |
|
143 |
UnaryMathFunction CreateSqrtFunction() { |
144 |
size_t actual_size; |
145 |
// Allocate buffer in executable space.
|
146 |
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, |
147 |
&actual_size, |
148 |
true));
|
149 |
// If SSE2 is not available, we can use libc's implementation to ensure
|
150 |
// consistency since code by fullcodegen's calls into runtime in that case.
|
151 |
if (buffer == NULL || !CpuFeatures::IsSupported(SSE2)) return &sqrt; |
152 |
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); |
153 |
// esp[1 * kPointerSize]: raw double input
|
154 |
// esp[0 * kPointerSize]: return address
|
155 |
// Move double input into registers.
|
156 |
{ |
157 |
CpuFeatureScope use_sse2(&masm, SSE2); |
158 |
__ movsd(xmm0, Operand(esp, 1 * kPointerSize));
|
159 |
__ sqrtsd(xmm0, xmm0); |
160 |
__ movsd(Operand(esp, 1 * kPointerSize), xmm0);
|
161 |
// Load result into floating point register as return value.
|
162 |
__ fld_d(Operand(esp, 1 * kPointerSize));
|
163 |
__ Ret(); |
164 |
} |
165 |
|
166 |
CodeDesc desc; |
167 |
masm.GetCode(&desc); |
168 |
ASSERT(!RelocInfo::RequiresRelocation(desc)); |
169 |
|
170 |
CPU::FlushICache(buffer, actual_size); |
171 |
OS::ProtectCode(buffer, actual_size); |
172 |
return FUNCTION_CAST<UnaryMathFunction>(buffer);
|
173 |
} |
174 |
|
175 |
|
176 |
// Helper functions for CreateMemMoveFunction.
|
177 |
#undef __
|
178 |
#define __ ACCESS_MASM(masm)
|
179 |
|
180 |
enum Direction { FORWARD, BACKWARD };
|
181 |
enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
|
182 |
|
183 |
// Expects registers:
|
184 |
// esi - source, aligned if alignment == ALIGNED
|
185 |
// edi - destination, always aligned
|
186 |
// ecx - count (copy size in bytes)
|
187 |
// edx - loop count (number of 64 byte chunks)
|
188 |
void MemMoveEmitMainLoop(MacroAssembler* masm,
|
189 |
Label* move_last_15, |
190 |
Direction direction, |
191 |
Alignment alignment) { |
192 |
Register src = esi; |
193 |
Register dst = edi; |
194 |
Register count = ecx; |
195 |
Register loop_count = edx; |
196 |
Label loop, move_last_31, move_last_63; |
197 |
__ cmp(loop_count, 0);
|
198 |
__ j(equal, &move_last_63); |
199 |
__ bind(&loop); |
200 |
// Main loop. Copy in 64 byte chunks.
|
201 |
if (direction == BACKWARD) __ sub(src, Immediate(0x40)); |
202 |
__ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
|
203 |
__ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
|
204 |
__ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
|
205 |
__ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
|
206 |
if (direction == FORWARD) __ add(src, Immediate(0x40)); |
207 |
if (direction == BACKWARD) __ sub(dst, Immediate(0x40)); |
208 |
__ movdqa(Operand(dst, 0x00), xmm0);
|
209 |
__ movdqa(Operand(dst, 0x10), xmm1);
|
210 |
__ movdqa(Operand(dst, 0x20), xmm2);
|
211 |
__ movdqa(Operand(dst, 0x30), xmm3);
|
212 |
if (direction == FORWARD) __ add(dst, Immediate(0x40)); |
213 |
__ dec(loop_count); |
214 |
__ j(not_zero, &loop); |
215 |
// At most 63 bytes left to copy.
|
216 |
__ bind(&move_last_63); |
217 |
__ test(count, Immediate(0x20));
|
218 |
__ j(zero, &move_last_31); |
219 |
if (direction == BACKWARD) __ sub(src, Immediate(0x20)); |
220 |
__ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
|
221 |
__ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
|
222 |
if (direction == FORWARD) __ add(src, Immediate(0x20)); |
223 |
if (direction == BACKWARD) __ sub(dst, Immediate(0x20)); |
224 |
__ movdqa(Operand(dst, 0x00), xmm0);
|
225 |
__ movdqa(Operand(dst, 0x10), xmm1);
|
226 |
if (direction == FORWARD) __ add(dst, Immediate(0x20)); |
227 |
// At most 31 bytes left to copy.
|
228 |
__ bind(&move_last_31); |
229 |
__ test(count, Immediate(0x10));
|
230 |
__ j(zero, move_last_15); |
231 |
if (direction == BACKWARD) __ sub(src, Immediate(0x10)); |
232 |
__ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
|
233 |
if (direction == FORWARD) __ add(src, Immediate(0x10)); |
234 |
if (direction == BACKWARD) __ sub(dst, Immediate(0x10)); |
235 |
__ movdqa(Operand(dst, 0), xmm0);
|
236 |
if (direction == FORWARD) __ add(dst, Immediate(0x10)); |
237 |
} |
238 |
|
239 |
|
240 |
void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
|
241 |
__ pop(esi); |
242 |
__ pop(edi); |
243 |
__ ret(0);
|
244 |
} |
245 |
|
246 |
|
247 |
#undef __
|
248 |
#define __ masm.
|
249 |
|
250 |
|
251 |
class LabelConverter { |
252 |
public:
|
253 |
explicit LabelConverter(byte* buffer) : buffer_(buffer) {}
|
254 |
int32_t address(Label* l) const {
|
255 |
return reinterpret_cast<int32_t>(buffer_) + l->pos(); |
256 |
} |
257 |
private:
|
258 |
byte* buffer_; |
259 |
}; |
260 |
|
261 |
|
262 |
OS::MemMoveFunction CreateMemMoveFunction() { |
263 |
size_t actual_size; |
264 |
// Allocate buffer in executable space.
|
265 |
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); |
266 |
if (buffer == NULL) return NULL; |
267 |
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); |
268 |
LabelConverter conv(buffer); |
269 |
|
270 |
// Generated code is put into a fixed, unmovable buffer, and not into
|
271 |
// the V8 heap. We can't, and don't, refer to any relocatable addresses
|
272 |
// (e.g. the JavaScript nan-object).
|
273 |
|
274 |
// 32-bit C declaration function calls pass arguments on stack.
|
275 |
|
276 |
// Stack layout:
|
277 |
// esp[12]: Third argument, size.
|
278 |
// esp[8]: Second argument, source pointer.
|
279 |
// esp[4]: First argument, destination pointer.
|
280 |
// esp[0]: return address
|
281 |
|
282 |
const int kDestinationOffset = 1 * kPointerSize; |
283 |
const int kSourceOffset = 2 * kPointerSize; |
284 |
const int kSizeOffset = 3 * kPointerSize; |
285 |
|
286 |
// When copying up to this many bytes, use special "small" handlers.
|
287 |
const size_t kSmallCopySize = 8; |
288 |
// When copying up to this many bytes, use special "medium" handlers.
|
289 |
const size_t kMediumCopySize = 63; |
290 |
// When non-overlapping region of src and dst is less than this,
|
291 |
// use a more careful implementation (slightly slower).
|
292 |
const size_t kMinMoveDistance = 16; |
293 |
// Note that these values are dictated by the implementation below,
|
294 |
// do not just change them and hope things will work!
|
295 |
|
296 |
int stack_offset = 0; // Update if we change the stack height. |
297 |
|
298 |
Label backward, backward_much_overlap; |
299 |
Label forward_much_overlap, small_size, medium_size, pop_and_return; |
300 |
__ push(edi); |
301 |
__ push(esi); |
302 |
stack_offset += 2 * kPointerSize;
|
303 |
Register dst = edi; |
304 |
Register src = esi; |
305 |
Register count = ecx; |
306 |
Register loop_count = edx; |
307 |
__ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); |
308 |
__ mov(src, Operand(esp, stack_offset + kSourceOffset)); |
309 |
__ mov(count, Operand(esp, stack_offset + kSizeOffset)); |
310 |
|
311 |
__ cmp(dst, src); |
312 |
__ j(equal, &pop_and_return); |
313 |
|
314 |
if (CpuFeatures::IsSupported(SSE2)) {
|
315 |
CpuFeatureScope sse2_scope(&masm, SSE2); |
316 |
__ prefetch(Operand(src, 0), 1); |
317 |
__ cmp(count, kSmallCopySize); |
318 |
__ j(below_equal, &small_size); |
319 |
__ cmp(count, kMediumCopySize); |
320 |
__ j(below_equal, &medium_size); |
321 |
__ cmp(dst, src); |
322 |
__ j(above, &backward); |
323 |
|
324 |
{ |
325 |
// |dst| is a lower address than |src|. Copy front-to-back.
|
326 |
Label unaligned_source, move_last_15, skip_last_move; |
327 |
__ mov(eax, src); |
328 |
__ sub(eax, dst); |
329 |
__ cmp(eax, kMinMoveDistance); |
330 |
__ j(below, &forward_much_overlap); |
331 |
// Copy first 16 bytes.
|
332 |
__ movdqu(xmm0, Operand(src, 0));
|
333 |
__ movdqu(Operand(dst, 0), xmm0);
|
334 |
// Determine distance to alignment: 16 - (dst & 0xF).
|
335 |
__ mov(edx, dst); |
336 |
__ and_(edx, 0xF);
|
337 |
__ neg(edx); |
338 |
__ add(edx, Immediate(16));
|
339 |
__ add(dst, edx); |
340 |
__ add(src, edx); |
341 |
__ sub(count, edx); |
342 |
// dst is now aligned. Main copy loop.
|
343 |
__ mov(loop_count, count); |
344 |
__ shr(loop_count, 6);
|
345 |
// Check if src is also aligned.
|
346 |
__ test(src, Immediate(0xF));
|
347 |
__ j(not_zero, &unaligned_source); |
348 |
// Copy loop for aligned source and destination.
|
349 |
MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED); |
350 |
// At most 15 bytes to copy. Copy 16 bytes at end of string.
|
351 |
__ bind(&move_last_15); |
352 |
__ and_(count, 0xF);
|
353 |
__ j(zero, &skip_last_move, Label::kNear); |
354 |
__ movdqu(xmm0, Operand(src, count, times_1, -0x10));
|
355 |
__ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
|
356 |
__ bind(&skip_last_move); |
357 |
MemMoveEmitPopAndReturn(&masm); |
358 |
|
359 |
// Copy loop for unaligned source and aligned destination.
|
360 |
__ bind(&unaligned_source); |
361 |
MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED); |
362 |
__ jmp(&move_last_15); |
363 |
|
364 |
// Less than kMinMoveDistance offset between dst and src.
|
365 |
Label loop_until_aligned, last_15_much_overlap; |
366 |
__ bind(&loop_until_aligned); |
367 |
__ mov_b(eax, Operand(src, 0));
|
368 |
__ inc(src); |
369 |
__ mov_b(Operand(dst, 0), eax);
|
370 |
__ inc(dst); |
371 |
__ dec(count); |
372 |
__ bind(&forward_much_overlap); // Entry point into this block.
|
373 |
__ test(dst, Immediate(0xF));
|
374 |
__ j(not_zero, &loop_until_aligned); |
375 |
// dst is now aligned, src can't be. Main copy loop.
|
376 |
__ mov(loop_count, count); |
377 |
__ shr(loop_count, 6);
|
378 |
MemMoveEmitMainLoop(&masm, &last_15_much_overlap, |
379 |
FORWARD, MOVE_UNALIGNED); |
380 |
__ bind(&last_15_much_overlap); |
381 |
__ and_(count, 0xF);
|
382 |
__ j(zero, &pop_and_return); |
383 |
__ cmp(count, kSmallCopySize); |
384 |
__ j(below_equal, &small_size); |
385 |
__ jmp(&medium_size); |
386 |
} |
387 |
|
388 |
{ |
389 |
// |dst| is a higher address than |src|. Copy backwards.
|
390 |
Label unaligned_source, move_first_15, skip_last_move; |
391 |
__ bind(&backward); |
392 |
// |dst| and |src| always point to the end of what's left to copy.
|
393 |
__ add(dst, count); |
394 |
__ add(src, count); |
395 |
__ mov(eax, dst); |
396 |
__ sub(eax, src); |
397 |
__ cmp(eax, kMinMoveDistance); |
398 |
__ j(below, &backward_much_overlap); |
399 |
// Copy last 16 bytes.
|
400 |
__ movdqu(xmm0, Operand(src, -0x10));
|
401 |
__ movdqu(Operand(dst, -0x10), xmm0);
|
402 |
// Find distance to alignment: dst & 0xF
|
403 |
__ mov(edx, dst); |
404 |
__ and_(edx, 0xF);
|
405 |
__ sub(dst, edx); |
406 |
__ sub(src, edx); |
407 |
__ sub(count, edx); |
408 |
// dst is now aligned. Main copy loop.
|
409 |
__ mov(loop_count, count); |
410 |
__ shr(loop_count, 6);
|
411 |
// Check if src is also aligned.
|
412 |
__ test(src, Immediate(0xF));
|
413 |
__ j(not_zero, &unaligned_source); |
414 |
// Copy loop for aligned source and destination.
|
415 |
MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED); |
416 |
// At most 15 bytes to copy. Copy 16 bytes at beginning of string.
|
417 |
__ bind(&move_first_15); |
418 |
__ and_(count, 0xF);
|
419 |
__ j(zero, &skip_last_move, Label::kNear); |
420 |
__ sub(src, count); |
421 |
__ sub(dst, count); |
422 |
__ movdqu(xmm0, Operand(src, 0));
|
423 |
__ movdqu(Operand(dst, 0), xmm0);
|
424 |
__ bind(&skip_last_move); |
425 |
MemMoveEmitPopAndReturn(&masm); |
426 |
|
427 |
// Copy loop for unaligned source and aligned destination.
|
428 |
__ bind(&unaligned_source); |
429 |
MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED); |
430 |
__ jmp(&move_first_15); |
431 |
|
432 |
// Less than kMinMoveDistance offset between dst and src.
|
433 |
Label loop_until_aligned, first_15_much_overlap; |
434 |
__ bind(&loop_until_aligned); |
435 |
__ dec(src); |
436 |
__ dec(dst); |
437 |
__ mov_b(eax, Operand(src, 0));
|
438 |
__ mov_b(Operand(dst, 0), eax);
|
439 |
__ dec(count); |
440 |
__ bind(&backward_much_overlap); // Entry point into this block.
|
441 |
__ test(dst, Immediate(0xF));
|
442 |
__ j(not_zero, &loop_until_aligned); |
443 |
// dst is now aligned, src can't be. Main copy loop.
|
444 |
__ mov(loop_count, count); |
445 |
__ shr(loop_count, 6);
|
446 |
MemMoveEmitMainLoop(&masm, &first_15_much_overlap, |
447 |
BACKWARD, MOVE_UNALIGNED); |
448 |
__ bind(&first_15_much_overlap); |
449 |
__ and_(count, 0xF);
|
450 |
__ j(zero, &pop_and_return); |
451 |
// Small/medium handlers expect dst/src to point to the beginning.
|
452 |
__ sub(dst, count); |
453 |
__ sub(src, count); |
454 |
__ cmp(count, kSmallCopySize); |
455 |
__ j(below_equal, &small_size); |
456 |
__ jmp(&medium_size); |
457 |
} |
458 |
{ |
459 |
// Special handlers for 9 <= copy_size < 64. No assumptions about
|
460 |
// alignment or move distance, so all reads must be unaligned and
|
461 |
// must happen before any writes.
|
462 |
Label medium_handlers, f9_16, f17_32, f33_48, f49_63; |
463 |
|
464 |
__ bind(&f9_16); |
465 |
__ movsd(xmm0, Operand(src, 0));
|
466 |
__ movsd(xmm1, Operand(src, count, times_1, -8));
|
467 |
__ movsd(Operand(dst, 0), xmm0);
|
468 |
__ movsd(Operand(dst, count, times_1, -8), xmm1);
|
469 |
MemMoveEmitPopAndReturn(&masm); |
470 |
|
471 |
__ bind(&f17_32); |
472 |
__ movdqu(xmm0, Operand(src, 0));
|
473 |
__ movdqu(xmm1, Operand(src, count, times_1, -0x10));
|
474 |
__ movdqu(Operand(dst, 0x00), xmm0);
|
475 |
__ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
|
476 |
MemMoveEmitPopAndReturn(&masm); |
477 |
|
478 |
__ bind(&f33_48); |
479 |
__ movdqu(xmm0, Operand(src, 0x00));
|
480 |
__ movdqu(xmm1, Operand(src, 0x10));
|
481 |
__ movdqu(xmm2, Operand(src, count, times_1, -0x10));
|
482 |
__ movdqu(Operand(dst, 0x00), xmm0);
|
483 |
__ movdqu(Operand(dst, 0x10), xmm1);
|
484 |
__ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
|
485 |
MemMoveEmitPopAndReturn(&masm); |
486 |
|
487 |
__ bind(&f49_63); |
488 |
__ movdqu(xmm0, Operand(src, 0x00));
|
489 |
__ movdqu(xmm1, Operand(src, 0x10));
|
490 |
__ movdqu(xmm2, Operand(src, 0x20));
|
491 |
__ movdqu(xmm3, Operand(src, count, times_1, -0x10));
|
492 |
__ movdqu(Operand(dst, 0x00), xmm0);
|
493 |
__ movdqu(Operand(dst, 0x10), xmm1);
|
494 |
__ movdqu(Operand(dst, 0x20), xmm2);
|
495 |
__ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
|
496 |
MemMoveEmitPopAndReturn(&masm); |
497 |
|
498 |
__ bind(&medium_handlers); |
499 |
__ dd(conv.address(&f9_16)); |
500 |
__ dd(conv.address(&f17_32)); |
501 |
__ dd(conv.address(&f33_48)); |
502 |
__ dd(conv.address(&f49_63)); |
503 |
|
504 |
__ bind(&medium_size); // Entry point into this block.
|
505 |
__ mov(eax, count); |
506 |
__ dec(eax); |
507 |
__ shr(eax, 4);
|
508 |
if (FLAG_debug_code) {
|
509 |
Label ok; |
510 |
__ cmp(eax, 3);
|
511 |
__ j(below_equal, &ok); |
512 |
__ int3(); |
513 |
__ bind(&ok); |
514 |
} |
515 |
__ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers))); |
516 |
__ jmp(eax); |
517 |
} |
518 |
{ |
519 |
// Specialized copiers for copy_size <= 8 bytes.
|
520 |
Label small_handlers, f0, f1, f2, f3, f4, f5_8; |
521 |
__ bind(&f0); |
522 |
MemMoveEmitPopAndReturn(&masm); |
523 |
|
524 |
__ bind(&f1); |
525 |
__ mov_b(eax, Operand(src, 0));
|
526 |
__ mov_b(Operand(dst, 0), eax);
|
527 |
MemMoveEmitPopAndReturn(&masm); |
528 |
|
529 |
__ bind(&f2); |
530 |
__ mov_w(eax, Operand(src, 0));
|
531 |
__ mov_w(Operand(dst, 0), eax);
|
532 |
MemMoveEmitPopAndReturn(&masm); |
533 |
|
534 |
__ bind(&f3); |
535 |
__ mov_w(eax, Operand(src, 0));
|
536 |
__ mov_b(edx, Operand(src, 2));
|
537 |
__ mov_w(Operand(dst, 0), eax);
|
538 |
__ mov_b(Operand(dst, 2), edx);
|
539 |
MemMoveEmitPopAndReturn(&masm); |
540 |
|
541 |
__ bind(&f4); |
542 |
__ mov(eax, Operand(src, 0));
|
543 |
__ mov(Operand(dst, 0), eax);
|
544 |
MemMoveEmitPopAndReturn(&masm); |
545 |
|
546 |
__ bind(&f5_8); |
547 |
__ mov(eax, Operand(src, 0));
|
548 |
__ mov(edx, Operand(src, count, times_1, -4));
|
549 |
__ mov(Operand(dst, 0), eax);
|
550 |
__ mov(Operand(dst, count, times_1, -4), edx);
|
551 |
MemMoveEmitPopAndReturn(&masm); |
552 |
|
553 |
__ bind(&small_handlers); |
554 |
__ dd(conv.address(&f0)); |
555 |
__ dd(conv.address(&f1)); |
556 |
__ dd(conv.address(&f2)); |
557 |
__ dd(conv.address(&f3)); |
558 |
__ dd(conv.address(&f4)); |
559 |
__ dd(conv.address(&f5_8)); |
560 |
__ dd(conv.address(&f5_8)); |
561 |
__ dd(conv.address(&f5_8)); |
562 |
__ dd(conv.address(&f5_8)); |
563 |
|
564 |
__ bind(&small_size); // Entry point into this block.
|
565 |
if (FLAG_debug_code) {
|
566 |
Label ok; |
567 |
__ cmp(count, 8);
|
568 |
__ j(below_equal, &ok); |
569 |
__ int3(); |
570 |
__ bind(&ok); |
571 |
} |
572 |
__ mov(eax, Operand(count, times_4, conv.address(&small_handlers))); |
573 |
__ jmp(eax); |
574 |
} |
575 |
} else {
|
576 |
// No SSE2.
|
577 |
Label forward; |
578 |
__ cmp(count, 0);
|
579 |
__ j(equal, &pop_and_return); |
580 |
__ cmp(dst, src); |
581 |
__ j(above, &backward); |
582 |
__ jmp(&forward); |
583 |
{ |
584 |
// Simple forward copier.
|
585 |
Label forward_loop_1byte, forward_loop_4byte; |
586 |
__ bind(&forward_loop_4byte); |
587 |
__ mov(eax, Operand(src, 0));
|
588 |
__ sub(count, Immediate(4));
|
589 |
__ add(src, Immediate(4));
|
590 |
__ mov(Operand(dst, 0), eax);
|
591 |
__ add(dst, Immediate(4));
|
592 |
__ bind(&forward); // Entry point.
|
593 |
__ cmp(count, 3);
|
594 |
__ j(above, &forward_loop_4byte); |
595 |
__ bind(&forward_loop_1byte); |
596 |
__ cmp(count, 0);
|
597 |
__ j(below_equal, &pop_and_return); |
598 |
__ mov_b(eax, Operand(src, 0));
|
599 |
__ dec(count); |
600 |
__ inc(src); |
601 |
__ mov_b(Operand(dst, 0), eax);
|
602 |
__ inc(dst); |
603 |
__ jmp(&forward_loop_1byte); |
604 |
} |
605 |
{ |
606 |
// Simple backward copier.
|
607 |
Label backward_loop_1byte, backward_loop_4byte, entry_shortcut; |
608 |
__ bind(&backward); |
609 |
__ add(src, count); |
610 |
__ add(dst, count); |
611 |
__ cmp(count, 3);
|
612 |
__ j(below_equal, &entry_shortcut); |
613 |
|
614 |
__ bind(&backward_loop_4byte); |
615 |
__ sub(src, Immediate(4));
|
616 |
__ sub(count, Immediate(4));
|
617 |
__ mov(eax, Operand(src, 0));
|
618 |
__ sub(dst, Immediate(4));
|
619 |
__ mov(Operand(dst, 0), eax);
|
620 |
__ cmp(count, 3);
|
621 |
__ j(above, &backward_loop_4byte); |
622 |
__ bind(&backward_loop_1byte); |
623 |
__ cmp(count, 0);
|
624 |
__ j(below_equal, &pop_and_return); |
625 |
__ bind(&entry_shortcut); |
626 |
__ dec(src); |
627 |
__ dec(count); |
628 |
__ mov_b(eax, Operand(src, 0));
|
629 |
__ dec(dst); |
630 |
__ mov_b(Operand(dst, 0), eax);
|
631 |
__ jmp(&backward_loop_1byte); |
632 |
} |
633 |
} |
634 |
|
635 |
__ bind(&pop_and_return); |
636 |
MemMoveEmitPopAndReturn(&masm); |
637 |
|
638 |
CodeDesc desc; |
639 |
masm.GetCode(&desc); |
640 |
ASSERT(!RelocInfo::RequiresRelocation(desc)); |
641 |
CPU::FlushICache(buffer, actual_size); |
642 |
OS::ProtectCode(buffer, actual_size); |
643 |
// TODO(jkummerow): It would be nice to register this code creation event
|
644 |
// with the PROFILE / GDBJIT system.
|
645 |
return FUNCTION_CAST<OS::MemMoveFunction>(buffer);
|
646 |
} |
647 |
|
648 |
|
649 |
#undef __
|
650 |
|
651 |
// -------------------------------------------------------------------------
|
652 |
// Code generators
|
653 |
|
654 |
#define __ ACCESS_MASM(masm)
|
655 |
|
656 |
|
657 |
void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
|
658 |
MacroAssembler* masm, AllocationSiteMode mode, |
659 |
Label* allocation_memento_found) { |
660 |
// ----------- S t a t e -------------
|
661 |
// -- eax : value
|
662 |
// -- ebx : target map
|
663 |
// -- ecx : key
|
664 |
// -- edx : receiver
|
665 |
// -- esp[0] : return address
|
666 |
// -----------------------------------
|
667 |
if (mode == TRACK_ALLOCATION_SITE) {
|
668 |
ASSERT(allocation_memento_found != NULL);
|
669 |
__ JumpIfJSArrayHasAllocationMemento(edx, edi, allocation_memento_found); |
670 |
} |
671 |
|
672 |
// Set transitioned map.
|
673 |
__ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); |
674 |
__ RecordWriteField(edx, |
675 |
HeapObject::kMapOffset, |
676 |
ebx, |
677 |
edi, |
678 |
kDontSaveFPRegs, |
679 |
EMIT_REMEMBERED_SET, |
680 |
OMIT_SMI_CHECK); |
681 |
} |
682 |
|
683 |
|
684 |
void ElementsTransitionGenerator::GenerateSmiToDouble(
|
685 |
MacroAssembler* masm, AllocationSiteMode mode, Label* fail) { |
686 |
// ----------- S t a t e -------------
|
687 |
// -- eax : value
|
688 |
// -- ebx : target map
|
689 |
// -- ecx : key
|
690 |
// -- edx : receiver
|
691 |
// -- esp[0] : return address
|
692 |
// -----------------------------------
|
693 |
Label loop, entry, convert_hole, gc_required, only_change_map; |
694 |
|
695 |
if (mode == TRACK_ALLOCATION_SITE) {
|
696 |
__ JumpIfJSArrayHasAllocationMemento(edx, edi, fail); |
697 |
} |
698 |
|
699 |
// Check for empty arrays, which only require a map transition and no changes
|
700 |
// to the backing store.
|
701 |
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
702 |
__ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); |
703 |
__ j(equal, &only_change_map); |
704 |
|
705 |
__ push(eax); |
706 |
__ push(ebx); |
707 |
|
708 |
__ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset)); |
709 |
|
710 |
// Allocate new FixedDoubleArray.
|
711 |
// edx: receiver
|
712 |
// edi: length of source FixedArray (smi-tagged)
|
713 |
AllocationFlags flags = |
714 |
static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT);
|
715 |
__ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi, |
716 |
REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags); |
717 |
|
718 |
// eax: destination FixedDoubleArray
|
719 |
// edi: number of elements
|
720 |
// edx: receiver
|
721 |
__ mov(FieldOperand(eax, HeapObject::kMapOffset), |
722 |
Immediate(masm->isolate()->factory()->fixed_double_array_map())); |
723 |
__ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi); |
724 |
__ mov(esi, FieldOperand(edx, JSObject::kElementsOffset)); |
725 |
// Replace receiver's backing store with newly created FixedDoubleArray.
|
726 |
__ mov(FieldOperand(edx, JSObject::kElementsOffset), eax); |
727 |
__ mov(ebx, eax); |
728 |
__ RecordWriteField(edx, |
729 |
JSObject::kElementsOffset, |
730 |
ebx, |
731 |
edi, |
732 |
kDontSaveFPRegs, |
733 |
EMIT_REMEMBERED_SET, |
734 |
OMIT_SMI_CHECK); |
735 |
|
736 |
__ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset)); |
737 |
|
738 |
// Prepare for conversion loop.
|
739 |
ExternalReference canonical_the_hole_nan_reference = |
740 |
ExternalReference::address_of_the_hole_nan(); |
741 |
XMMRegister the_hole_nan = xmm1; |
742 |
if (CpuFeatures::IsSupported(SSE2)) {
|
743 |
CpuFeatureScope use_sse2(masm, SSE2); |
744 |
__ movsd(the_hole_nan, |
745 |
Operand::StaticVariable(canonical_the_hole_nan_reference)); |
746 |
} |
747 |
__ jmp(&entry); |
748 |
|
749 |
// Call into runtime if GC is required.
|
750 |
__ bind(&gc_required); |
751 |
// Restore registers before jumping into runtime.
|
752 |
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
753 |
__ pop(ebx); |
754 |
__ pop(eax); |
755 |
__ jmp(fail); |
756 |
|
757 |
// Convert and copy elements
|
758 |
// esi: source FixedArray
|
759 |
__ bind(&loop); |
760 |
__ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize)); |
761 |
// ebx: current element from source
|
762 |
// edi: index of current element
|
763 |
__ JumpIfNotSmi(ebx, &convert_hole); |
764 |
|
765 |
// Normal smi, convert it to double and store.
|
766 |
__ SmiUntag(ebx); |
767 |
if (CpuFeatures::IsSupported(SSE2)) {
|
768 |
CpuFeatureScope fscope(masm, SSE2); |
769 |
__ Cvtsi2sd(xmm0, ebx); |
770 |
__ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize), |
771 |
xmm0); |
772 |
} else {
|
773 |
__ push(ebx); |
774 |
__ fild_s(Operand(esp, 0));
|
775 |
__ pop(ebx); |
776 |
__ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize)); |
777 |
} |
778 |
__ jmp(&entry); |
779 |
|
780 |
// Found hole, store hole_nan_as_double instead.
|
781 |
__ bind(&convert_hole); |
782 |
|
783 |
if (FLAG_debug_code) {
|
784 |
__ cmp(ebx, masm->isolate()->factory()->the_hole_value()); |
785 |
__ Assert(equal, kObjectFoundInSmiOnlyArray); |
786 |
} |
787 |
|
788 |
if (CpuFeatures::IsSupported(SSE2)) {
|
789 |
CpuFeatureScope use_sse2(masm, SSE2); |
790 |
__ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize), |
791 |
the_hole_nan); |
792 |
} else {
|
793 |
__ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference)); |
794 |
__ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize)); |
795 |
} |
796 |
|
797 |
__ bind(&entry); |
798 |
__ sub(edi, Immediate(Smi::FromInt(1)));
|
799 |
__ j(not_sign, &loop); |
800 |
|
801 |
__ pop(ebx); |
802 |
__ pop(eax); |
803 |
|
804 |
// Restore esi.
|
805 |
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
806 |
|
807 |
__ bind(&only_change_map); |
808 |
// eax: value
|
809 |
// ebx: target map
|
810 |
// Set transitioned map.
|
811 |
__ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); |
812 |
__ RecordWriteField(edx, |
813 |
HeapObject::kMapOffset, |
814 |
ebx, |
815 |
edi, |
816 |
kDontSaveFPRegs, |
817 |
OMIT_REMEMBERED_SET, |
818 |
OMIT_SMI_CHECK); |
819 |
} |
820 |
|
821 |
|
822 |
void ElementsTransitionGenerator::GenerateDoubleToObject(
|
823 |
MacroAssembler* masm, AllocationSiteMode mode, Label* fail) { |
824 |
// ----------- S t a t e -------------
|
825 |
// -- eax : value
|
826 |
// -- ebx : target map
|
827 |
// -- ecx : key
|
828 |
// -- edx : receiver
|
829 |
// -- esp[0] : return address
|
830 |
// -----------------------------------
|
831 |
Label loop, entry, convert_hole, gc_required, only_change_map, success; |
832 |
|
833 |
if (mode == TRACK_ALLOCATION_SITE) {
|
834 |
__ JumpIfJSArrayHasAllocationMemento(edx, edi, fail); |
835 |
} |
836 |
|
837 |
// Check for empty arrays, which only require a map transition and no changes
|
838 |
// to the backing store.
|
839 |
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
840 |
__ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); |
841 |
__ j(equal, &only_change_map); |
842 |
|
843 |
__ push(eax); |
844 |
__ push(edx); |
845 |
__ push(ebx); |
846 |
|
847 |
__ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset)); |
848 |
|
849 |
// Allocate new FixedArray.
|
850 |
// ebx: length of source FixedDoubleArray (smi-tagged)
|
851 |
__ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize)); |
852 |
__ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT); |
853 |
|
854 |
// eax: destination FixedArray
|
855 |
// ebx: number of elements
|
856 |
__ mov(FieldOperand(eax, HeapObject::kMapOffset), |
857 |
Immediate(masm->isolate()->factory()->fixed_array_map())); |
858 |
__ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx); |
859 |
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
860 |
|
861 |
__ jmp(&entry); |
862 |
|
863 |
// ebx: target map
|
864 |
// edx: receiver
|
865 |
// Set transitioned map.
|
866 |
__ bind(&only_change_map); |
867 |
__ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); |
868 |
__ RecordWriteField(edx, |
869 |
HeapObject::kMapOffset, |
870 |
ebx, |
871 |
edi, |
872 |
kDontSaveFPRegs, |
873 |
OMIT_REMEMBERED_SET, |
874 |
OMIT_SMI_CHECK); |
875 |
__ jmp(&success); |
876 |
|
877 |
// Call into runtime if GC is required.
|
878 |
__ bind(&gc_required); |
879 |
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
880 |
__ pop(ebx); |
881 |
__ pop(edx); |
882 |
__ pop(eax); |
883 |
__ jmp(fail); |
884 |
|
885 |
// Box doubles into heap numbers.
|
886 |
// edi: source FixedDoubleArray
|
887 |
// eax: destination FixedArray
|
888 |
__ bind(&loop); |
889 |
// ebx: index of current element (smi-tagged)
|
890 |
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
|
891 |
__ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32)); |
892 |
__ j(equal, &convert_hole); |
893 |
|
894 |
// Non-hole double, copy value into a heap number.
|
895 |
__ AllocateHeapNumber(edx, esi, no_reg, &gc_required); |
896 |
// edx: new heap number
|
897 |
if (CpuFeatures::IsSupported(SSE2)) {
|
898 |
CpuFeatureScope fscope(masm, SSE2); |
899 |
__ movsd(xmm0, |
900 |
FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize)); |
901 |
__ movsd(FieldOperand(edx, HeapNumber::kValueOffset), xmm0); |
902 |
} else {
|
903 |
__ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize)); |
904 |
__ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi); |
905 |
__ mov(esi, FieldOperand(edi, ebx, times_4, offset)); |
906 |
__ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi); |
907 |
} |
908 |
__ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx); |
909 |
__ mov(esi, ebx); |
910 |
__ RecordWriteArray(eax, |
911 |
edx, |
912 |
esi, |
913 |
kDontSaveFPRegs, |
914 |
EMIT_REMEMBERED_SET, |
915 |
OMIT_SMI_CHECK); |
916 |
__ jmp(&entry, Label::kNear); |
917 |
|
918 |
// Replace the-hole NaN with the-hole pointer.
|
919 |
__ bind(&convert_hole); |
920 |
__ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), |
921 |
masm->isolate()->factory()->the_hole_value()); |
922 |
|
923 |
__ bind(&entry); |
924 |
__ sub(ebx, Immediate(Smi::FromInt(1)));
|
925 |
__ j(not_sign, &loop); |
926 |
|
927 |
__ pop(ebx); |
928 |
__ pop(edx); |
929 |
// ebx: target map
|
930 |
// edx: receiver
|
931 |
// Set transitioned map.
|
932 |
__ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); |
933 |
__ RecordWriteField(edx, |
934 |
HeapObject::kMapOffset, |
935 |
ebx, |
936 |
edi, |
937 |
kDontSaveFPRegs, |
938 |
OMIT_REMEMBERED_SET, |
939 |
OMIT_SMI_CHECK); |
940 |
// Replace receiver's backing store with newly created and filled FixedArray.
|
941 |
__ mov(FieldOperand(edx, JSObject::kElementsOffset), eax); |
942 |
__ RecordWriteField(edx, |
943 |
JSObject::kElementsOffset, |
944 |
eax, |
945 |
edi, |
946 |
kDontSaveFPRegs, |
947 |
EMIT_REMEMBERED_SET, |
948 |
OMIT_SMI_CHECK); |
949 |
|
950 |
// Restore registers.
|
951 |
__ pop(eax); |
952 |
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
953 |
|
954 |
__ bind(&success); |
955 |
} |
956 |
|
957 |
|
958 |
void StringCharLoadGenerator::Generate(MacroAssembler* masm,
|
959 |
Factory* factory, |
960 |
Register string,
|
961 |
Register index, |
962 |
Register result, |
963 |
Label* call_runtime) { |
964 |
// Fetch the instance type of the receiver into result register.
|
965 |
__ mov(result, FieldOperand(string, HeapObject::kMapOffset));
|
966 |
__ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
967 |
|
968 |
// We need special handling for indirect strings.
|
969 |
Label check_sequential; |
970 |
__ test(result, Immediate(kIsIndirectStringMask)); |
971 |
__ j(zero, &check_sequential, Label::kNear); |
972 |
|
973 |
// Dispatch on the indirect string shape: slice or cons.
|
974 |
Label cons_string; |
975 |
__ test(result, Immediate(kSlicedNotConsMask)); |
976 |
__ j(zero, &cons_string, Label::kNear); |
977 |
|
978 |
// Handle slices.
|
979 |
Label indirect_string_loaded; |
980 |
__ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
|
981 |
__ SmiUntag(result); |
982 |
__ add(index, result); |
983 |
__ mov(string, FieldOperand(string, SlicedString::kParentOffset)); |
984 |
__ jmp(&indirect_string_loaded, Label::kNear); |
985 |
|
986 |
// Handle cons strings.
|
987 |
// Check whether the right hand side is the empty string (i.e. if
|
988 |
// this is really a flat string in a cons string). If that is not
|
989 |
// the case we would rather go to the runtime system now to flatten
|
990 |
// the string.
|
991 |
__ bind(&cons_string); |
992 |
__ cmp(FieldOperand(string, ConsString::kSecondOffset),
|
993 |
Immediate(factory->empty_string())); |
994 |
__ j(not_equal, call_runtime); |
995 |
__ mov(string, FieldOperand(string, ConsString::kFirstOffset)); |
996 |
|
997 |
__ bind(&indirect_string_loaded); |
998 |
__ mov(result, FieldOperand(string, HeapObject::kMapOffset));
|
999 |
__ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
1000 |
|
1001 |
// Distinguish sequential and external strings. Only these two string
|
1002 |
// representations can reach here (slices and flat cons strings have been
|
1003 |
// reduced to the underlying sequential or external string).
|
1004 |
Label seq_string; |
1005 |
__ bind(&check_sequential); |
1006 |
STATIC_ASSERT(kSeqStringTag == 0);
|
1007 |
__ test(result, Immediate(kStringRepresentationMask)); |
1008 |
__ j(zero, &seq_string, Label::kNear); |
1009 |
|
1010 |
// Handle external strings.
|
1011 |
Label ascii_external, done; |
1012 |
if (FLAG_debug_code) {
|
1013 |
// Assert that we do not have a cons or slice (indirect strings) here.
|
1014 |
// Sequential strings have already been ruled out.
|
1015 |
__ test(result, Immediate(kIsIndirectStringMask)); |
1016 |
__ Assert(zero, kExternalStringExpectedButNotFound); |
1017 |
} |
1018 |
// Rule out short external strings.
|
1019 |
STATIC_CHECK(kShortExternalStringTag != 0);
|
1020 |
__ test_b(result, kShortExternalStringMask); |
1021 |
__ j(not_zero, call_runtime); |
1022 |
// Check encoding.
|
1023 |
STATIC_ASSERT(kTwoByteStringTag == 0);
|
1024 |
__ test_b(result, kStringEncodingMask); |
1025 |
__ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
|
1026 |
__ j(not_equal, &ascii_external, Label::kNear); |
1027 |
// Two-byte string.
|
1028 |
__ movzx_w(result, Operand(result, index, times_2, 0));
|
1029 |
__ jmp(&done, Label::kNear); |
1030 |
__ bind(&ascii_external); |
1031 |
// Ascii string.
|
1032 |
__ movzx_b(result, Operand(result, index, times_1, 0));
|
1033 |
__ jmp(&done, Label::kNear); |
1034 |
|
1035 |
// Dispatch on the encoding: ASCII or two-byte.
|
1036 |
Label ascii; |
1037 |
__ bind(&seq_string); |
1038 |
STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
|
1039 |
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
|
1040 |
__ test(result, Immediate(kStringEncodingMask)); |
1041 |
__ j(not_zero, &ascii, Label::kNear); |
1042 |
|
1043 |
// Two-byte string.
|
1044 |
// Load the two-byte character code into the result register.
|
1045 |
__ movzx_w(result, FieldOperand(string,
|
1046 |
index, |
1047 |
times_2, |
1048 |
SeqTwoByteString::kHeaderSize)); |
1049 |
__ jmp(&done, Label::kNear); |
1050 |
|
1051 |
// Ascii string.
|
1052 |
// Load the byte into the result register.
|
1053 |
__ bind(&ascii); |
1054 |
__ movzx_b(result, FieldOperand(string,
|
1055 |
index, |
1056 |
times_1, |
1057 |
SeqOneByteString::kHeaderSize)); |
1058 |
__ bind(&done); |
1059 |
} |
1060 |
|
1061 |
|
1062 |
static Operand ExpConstant(int index) { |
1063 |
return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
|
1064 |
} |
1065 |
|
1066 |
|
1067 |
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
|
1068 |
XMMRegister input, |
1069 |
XMMRegister result, |
1070 |
XMMRegister double_scratch, |
1071 |
Register temp1, |
1072 |
Register temp2) { |
1073 |
ASSERT(!input.is(double_scratch)); |
1074 |
ASSERT(!input.is(result)); |
1075 |
ASSERT(!result.is(double_scratch)); |
1076 |
ASSERT(!temp1.is(temp2)); |
1077 |
ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); |
1078 |
|
1079 |
Label done; |
1080 |
|
1081 |
__ movsd(double_scratch, ExpConstant(0));
|
1082 |
__ xorpd(result, result); |
1083 |
__ ucomisd(double_scratch, input); |
1084 |
__ j(above_equal, &done); |
1085 |
__ ucomisd(input, ExpConstant(1));
|
1086 |
__ movsd(result, ExpConstant(2));
|
1087 |
__ j(above_equal, &done); |
1088 |
__ movsd(double_scratch, ExpConstant(3));
|
1089 |
__ movsd(result, ExpConstant(4));
|
1090 |
__ mulsd(double_scratch, input); |
1091 |
__ addsd(double_scratch, result); |
1092 |
__ movd(temp2, double_scratch); |
1093 |
__ subsd(double_scratch, result); |
1094 |
__ movsd(result, ExpConstant(6));
|
1095 |
__ mulsd(double_scratch, ExpConstant(5));
|
1096 |
__ subsd(double_scratch, input); |
1097 |
__ subsd(result, double_scratch); |
1098 |
__ movsd(input, double_scratch); |
1099 |
__ mulsd(input, double_scratch); |
1100 |
__ mulsd(result, input); |
1101 |
__ mov(temp1, temp2); |
1102 |
__ mulsd(result, ExpConstant(7));
|
1103 |
__ subsd(result, double_scratch); |
1104 |
__ add(temp1, Immediate(0x1ff800));
|
1105 |
__ addsd(result, ExpConstant(8));
|
1106 |
__ and_(temp2, Immediate(0x7ff));
|
1107 |
__ shr(temp1, 11);
|
1108 |
__ shl(temp1, 20);
|
1109 |
__ movd(input, temp1); |
1110 |
__ pshufd(input, input, static_cast<uint8_t>(0xe1)); // Order: 11 10 00 01 |
1111 |
__ movsd(double_scratch, Operand::StaticArray( |
1112 |
temp2, times_8, ExternalReference::math_exp_log_table())); |
1113 |
__ por(input, double_scratch); |
1114 |
__ mulsd(result, input); |
1115 |
__ bind(&done); |
1116 |
} |
1117 |
|
1118 |
#undef __
|
1119 |
|
1120 |
|
1121 |
static byte* GetNoCodeAgeSequence(uint32_t* length) {
|
1122 |
static bool initialized = false; |
1123 |
static byte sequence[kNoCodeAgeSequenceLength];
|
1124 |
*length = kNoCodeAgeSequenceLength; |
1125 |
if (!initialized) {
|
1126 |
// The sequence of instructions that is patched out for aging code is the
|
1127 |
// following boilerplate stack-building prologue that is found both in
|
1128 |
// FUNCTION and OPTIMIZED_FUNCTION code:
|
1129 |
CodePatcher patcher(sequence, kNoCodeAgeSequenceLength); |
1130 |
patcher.masm()->push(ebp); |
1131 |
patcher.masm()->mov(ebp, esp); |
1132 |
patcher.masm()->push(esi); |
1133 |
patcher.masm()->push(edi); |
1134 |
initialized = true;
|
1135 |
} |
1136 |
return sequence;
|
1137 |
} |
1138 |
|
1139 |
|
1140 |
bool Code::IsYoungSequence(byte* sequence) {
|
1141 |
uint32_t young_length; |
1142 |
byte* young_sequence = GetNoCodeAgeSequence(&young_length); |
1143 |
bool result = (!memcmp(sequence, young_sequence, young_length));
|
1144 |
ASSERT(result || *sequence == kCallOpcode); |
1145 |
return result;
|
1146 |
} |
1147 |
|
1148 |
|
1149 |
void Code::GetCodeAgeAndParity(byte* sequence, Age* age,
|
1150 |
MarkingParity* parity) { |
1151 |
if (IsYoungSequence(sequence)) {
|
1152 |
*age = kNoAgeCodeAge; |
1153 |
*parity = NO_MARKING_PARITY; |
1154 |
} else {
|
1155 |
sequence++; // Skip the kCallOpcode byte
|
1156 |
Address target_address = sequence + *reinterpret_cast<int*>(sequence) + |
1157 |
Assembler::kCallTargetAddressOffset; |
1158 |
Code* stub = GetCodeFromTargetAddress(target_address); |
1159 |
GetCodeAgeAndParity(stub, age, parity); |
1160 |
} |
1161 |
} |
1162 |
|
1163 |
|
1164 |
void Code::PatchPlatformCodeAge(Isolate* isolate,
|
1165 |
byte* sequence, |
1166 |
Code::Age age, |
1167 |
MarkingParity parity) { |
1168 |
uint32_t young_length; |
1169 |
byte* young_sequence = GetNoCodeAgeSequence(&young_length); |
1170 |
if (age == kNoAgeCodeAge) {
|
1171 |
CopyBytes(sequence, young_sequence, young_length); |
1172 |
CPU::FlushICache(sequence, young_length); |
1173 |
} else {
|
1174 |
Code* stub = GetCodeAgeStub(isolate, age, parity); |
1175 |
CodePatcher patcher(sequence, young_length); |
1176 |
patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32); |
1177 |
} |
1178 |
} |
1179 |
|
1180 |
|
1181 |
} } // namespace v8::internal
|
1182 |
|
1183 |
#endif // V8_TARGET_ARCH_IA32 |