blob: d56223889351751fd480f95f42146ff53cb39d7e [file] [log] [blame]
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000032#include "codegen.h"
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000033#include "heap.h"
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000034#include "macro-assembler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
ricow@chromium.org30ce4112010-05-31 10:38:25 +000039
40// -------------------------------------------------------------------------
41// Platform-specific RuntimeCallHelper functions.
42
kasperl@chromium.orga5551262010-12-07 12:49:48 +000043void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000044 masm->EnterFrame(StackFrame::INTERNAL);
45 ASSERT(!masm->has_frame());
46 masm->set_has_frame(true);
ricow@chromium.org30ce4112010-05-31 10:38:25 +000047}
48
49
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000051 masm->LeaveFrame(StackFrame::INTERNAL);
52 ASSERT(masm->has_frame());
53 masm->set_has_frame(false);
ricow@chromium.org30ce4112010-05-31 10:38:25 +000054}
55
56
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000057#define __ masm.
58
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000059
yangguo@chromium.org154ff992012-03-13 08:09:54 +000060UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000061 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);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000097 ASSERT(!RelocInfo::RequiresRelocation(desc));
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000098
99 CPU::FlushICache(buffer, actual_size);
100 OS::ProtectCode(buffer, actual_size);
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000101 return FUNCTION_CAST<UnaryMathFunction>(buffer);
102}
103
104
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000105UnaryMathFunction 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 {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000117 CpuFeatureScope use_sse2(&masm, SSE2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000118 XMMRegister input = xmm1;
119 XMMRegister result = xmm2;
120 __ movdbl(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 __ movdbl(Operand(esp, 1 * kPointerSize), result);
129 __ fld_d(Operand(esp, 1 * kPointerSize));
130 __ Ret();
131 }
132
133 CodeDesc desc;
134 masm.GetCode(&desc);
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000135 ASSERT(!RelocInfo::RequiresRelocation(desc));
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000136
137 CPU::FlushICache(buffer, actual_size);
138 OS::ProtectCode(buffer, actual_size);
139 return FUNCTION_CAST<UnaryMathFunction>(buffer);
140}
141
142
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000143UnaryMathFunction 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 {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000157 CpuFeatureScope use_sse2(&masm, SSE2);
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000158 __ movdbl(xmm0, Operand(esp, 1 * kPointerSize));
159 __ sqrtsd(xmm0, xmm0);
160 __ movdbl(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);
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000168 ASSERT(!RelocInfo::RequiresRelocation(desc));
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000169
170 CPU::FlushICache(buffer, actual_size);
171 OS::ProtectCode(buffer, actual_size);
172 return FUNCTION_CAST<UnaryMathFunction>(buffer);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000173}
174
175
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000176// Helper functions for CreateMemMoveFunction.
177#undef __
178#define __ ACCESS_MASM(masm)
179
180// Keep around global pointers to these objects so that Valgrind won't complain.
181static size_t* medium_handlers = NULL;
182static size_t* small_handlers = NULL;
183
184
185enum Direction { FORWARD, BACKWARD };
186enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
187
188// Expects registers:
189// esi - source, aligned if alignment == ALIGNED
190// edi - destination, always aligned
191// ecx - count (copy size in bytes)
192// edx - loop count (number of 64 byte chunks)
193void MemMoveEmitMainLoop(MacroAssembler* masm,
194 Label* move_last_15,
195 Direction direction,
196 Alignment alignment) {
197 Register src = esi;
198 Register dst = edi;
199 Register count = ecx;
200 Register loop_count = edx;
201 Label loop, move_last_31, move_last_63;
202 __ cmp(loop_count, 0);
203 __ j(equal, &move_last_63);
204 __ bind(&loop);
205 // Main loop. Copy in 64 byte chunks.
206 if (direction == BACKWARD) __ sub(src, Immediate(0x40));
207 __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
208 __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
209 __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
210 __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
211 if (direction == FORWARD) __ add(src, Immediate(0x40));
212 if (direction == BACKWARD) __ sub(dst, Immediate(0x40));
213 __ movdqa(Operand(dst, 0x00), xmm0);
214 __ movdqa(Operand(dst, 0x10), xmm1);
215 __ movdqa(Operand(dst, 0x20), xmm2);
216 __ movdqa(Operand(dst, 0x30), xmm3);
217 if (direction == FORWARD) __ add(dst, Immediate(0x40));
218 __ dec(loop_count);
219 __ j(not_zero, &loop);
220 // At most 63 bytes left to copy.
221 __ bind(&move_last_63);
222 __ test(count, Immediate(0x20));
223 __ j(zero, &move_last_31);
224 if (direction == BACKWARD) __ sub(src, Immediate(0x20));
225 __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
226 __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
227 if (direction == FORWARD) __ add(src, Immediate(0x20));
228 if (direction == BACKWARD) __ sub(dst, Immediate(0x20));
229 __ movdqa(Operand(dst, 0x00), xmm0);
230 __ movdqa(Operand(dst, 0x10), xmm1);
231 if (direction == FORWARD) __ add(dst, Immediate(0x20));
232 // At most 31 bytes left to copy.
233 __ bind(&move_last_31);
234 __ test(count, Immediate(0x10));
235 __ j(zero, move_last_15);
236 if (direction == BACKWARD) __ sub(src, Immediate(0x10));
237 __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
238 if (direction == FORWARD) __ add(src, Immediate(0x10));
239 if (direction == BACKWARD) __ sub(dst, Immediate(0x10));
240 __ movdqa(Operand(dst, 0), xmm0);
241 if (direction == FORWARD) __ add(dst, Immediate(0x10));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000242}
243
244
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000245void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
246 __ pop(esi);
247 __ pop(edi);
248 __ ret(0);
249}
250
251
252#undef __
253#define __ masm.
254
255
256OS::MemMoveFunction CreateMemMoveFunction() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000257 size_t actual_size;
258 // Allocate buffer in executable space.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000259 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
260 if (buffer == NULL) return NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000261 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000262
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000263 // Generated code is put into a fixed, unmovable buffer, and not into
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000264 // the V8 heap. We can't, and don't, refer to any relocatable addresses
265 // (e.g. the JavaScript nan-object).
266
267 // 32-bit C declaration function calls pass arguments on stack.
268
269 // Stack layout:
270 // esp[12]: Third argument, size.
271 // esp[8]: Second argument, source pointer.
272 // esp[4]: First argument, destination pointer.
273 // esp[0]: return address
274
275 const int kDestinationOffset = 1 * kPointerSize;
276 const int kSourceOffset = 2 * kPointerSize;
277 const int kSizeOffset = 3 * kPointerSize;
278
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000279 // When copying up to this many bytes, use special "small" handlers.
280 const size_t kSmallCopySize = 8;
281 // When copying up to this many bytes, use special "medium" handlers.
282 const size_t kMediumCopySize = 63;
283 // When non-overlapping region of src and dst is less than this,
284 // use a more careful implementation (slightly slower).
285 const size_t kMinMoveDistance = 16;
286 // Note that these values are dictated by the implementation below,
287 // do not just change them and hope things will work!
288
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000289 int stack_offset = 0; // Update if we change the stack height.
290
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000291 Label backward, backward_much_overlap;
292 Label forward_much_overlap, small_size, medium_size, pop_and_return;
293 __ push(edi);
294 __ push(esi);
295 stack_offset += 2 * kPointerSize;
296 Register dst = edi;
297 Register src = esi;
298 Register count = ecx;
299 Register loop_count = edx;
300 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
301 __ mov(src, Operand(esp, stack_offset + kSourceOffset));
302 __ mov(count, Operand(esp, stack_offset + kSizeOffset));
303
304 __ cmp(dst, src);
305 __ j(equal, &pop_and_return);
306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000307 if (CpuFeatures::IsSupported(SSE2)) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000308 CpuFeatureScope sse2_scope(&masm, SSE2);
309 __ prefetch(Operand(src, 0), 1);
310 __ cmp(count, kSmallCopySize);
311 __ j(below_equal, &small_size);
312 __ cmp(count, kMediumCopySize);
313 __ j(below_equal, &medium_size);
314 __ cmp(dst, src);
315 __ j(above, &backward);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000316
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000317 {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000318 // |dst| is a lower address than |src|. Copy front-to-back.
319 Label unaligned_source, move_last_15, skip_last_move;
320 __ mov(eax, src);
321 __ sub(eax, dst);
322 __ cmp(eax, kMinMoveDistance);
323 __ j(below, &forward_much_overlap);
324 // Copy first 16 bytes.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000325 __ movdqu(xmm0, Operand(src, 0));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000326 __ movdqu(Operand(dst, 0), xmm0);
327 // Determine distance to alignment: 16 - (dst & 0xF).
328 __ mov(edx, dst);
329 __ and_(edx, 0xF);
330 __ neg(edx);
331 __ add(edx, Immediate(16));
332 __ add(dst, edx);
333 __ add(src, edx);
334 __ sub(count, edx);
335 // dst is now aligned. Main copy loop.
336 __ mov(loop_count, count);
337 __ shr(loop_count, 6);
338 // Check if src is also aligned.
339 __ test(src, Immediate(0xF));
340 __ j(not_zero, &unaligned_source);
341 // Copy loop for aligned source and destination.
342 MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000343 // At most 15 bytes to copy. Copy 16 bytes at end of string.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000344 __ bind(&move_last_15);
345 __ and_(count, 0xF);
346 __ j(zero, &skip_last_move, Label::kNear);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000347 __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
348 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000349 __ bind(&skip_last_move);
350 MemMoveEmitPopAndReturn(&masm);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000351
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000352 // Copy loop for unaligned source and aligned destination.
353 __ bind(&unaligned_source);
354 MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
355 __ jmp(&move_last_15);
356
357 // Less than kMinMoveDistance offset between dst and src.
358 Label loop_until_aligned, last_15_much_overlap;
359 __ bind(&loop_until_aligned);
360 __ mov_b(eax, Operand(src, 0));
361 __ inc(src);
362 __ mov_b(Operand(dst, 0), eax);
363 __ inc(dst);
364 __ dec(count);
365 __ bind(&forward_much_overlap); // Entry point into this block.
366 __ test(dst, Immediate(0xF));
367 __ j(not_zero, &loop_until_aligned);
368 // dst is now aligned, src can't be. Main copy loop.
369 __ mov(loop_count, count);
370 __ shr(loop_count, 6);
371 MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
372 FORWARD, MOVE_UNALIGNED);
373 __ bind(&last_15_much_overlap);
374 __ and_(count, 0xF);
375 __ j(zero, &pop_and_return);
376 __ cmp(count, kSmallCopySize);
377 __ j(below_equal, &small_size);
378 __ jmp(&medium_size);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000379 }
380
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000381 {
382 // |dst| is a higher address than |src|. Copy backwards.
383 Label unaligned_source, move_first_15, skip_last_move;
384 __ bind(&backward);
385 // |dst| and |src| always point to the end of what's left to copy.
386 __ add(dst, count);
387 __ add(src, count);
388 __ mov(eax, dst);
389 __ sub(eax, src);
390 __ cmp(eax, kMinMoveDistance);
391 __ j(below, &backward_much_overlap);
392 // Copy last 16 bytes.
393 __ movdqu(xmm0, Operand(src, -0x10));
394 __ movdqu(Operand(dst, -0x10), xmm0);
395 // Find distance to alignment: dst & 0xF
396 __ mov(edx, dst);
397 __ and_(edx, 0xF);
398 __ sub(dst, edx);
399 __ sub(src, edx);
400 __ sub(count, edx);
401 // dst is now aligned. Main copy loop.
402 __ mov(loop_count, count);
403 __ shr(loop_count, 6);
404 // Check if src is also aligned.
405 __ test(src, Immediate(0xF));
406 __ j(not_zero, &unaligned_source);
407 // Copy loop for aligned source and destination.
408 MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
409 // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
410 __ bind(&move_first_15);
411 __ and_(count, 0xF);
412 __ j(zero, &skip_last_move, Label::kNear);
413 __ sub(src, count);
414 __ sub(dst, count);
415 __ movdqu(xmm0, Operand(src, 0));
416 __ movdqu(Operand(dst, 0), xmm0);
417 __ bind(&skip_last_move);
418 MemMoveEmitPopAndReturn(&masm);
419
420 // Copy loop for unaligned source and aligned destination.
421 __ bind(&unaligned_source);
422 MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
423 __ jmp(&move_first_15);
424
425 // Less than kMinMoveDistance offset between dst and src.
426 Label loop_until_aligned, first_15_much_overlap;
427 __ bind(&loop_until_aligned);
428 __ dec(src);
429 __ dec(dst);
430 __ mov_b(eax, Operand(src, 0));
431 __ mov_b(Operand(dst, 0), eax);
432 __ dec(count);
433 __ bind(&backward_much_overlap); // Entry point into this block.
434 __ test(dst, Immediate(0xF));
435 __ j(not_zero, &loop_until_aligned);
436 // dst is now aligned, src can't be. Main copy loop.
437 __ mov(loop_count, count);
438 __ shr(loop_count, 6);
439 MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
440 BACKWARD, MOVE_UNALIGNED);
441 __ bind(&first_15_much_overlap);
442 __ and_(count, 0xF);
443 __ j(zero, &pop_and_return);
444 // Small/medium handlers expect dst/src to point to the beginning.
445 __ sub(dst, count);
446 __ sub(src, count);
447 __ cmp(count, kSmallCopySize);
448 __ j(below_equal, &small_size);
449 __ jmp(&medium_size);
450 }
451 {
452 // Special handlers for 9 <= copy_size < 64. No assumptions about
453 // alignment or move distance, so all reads must be unaligned and
454 // must happen before any writes.
455 Label f9_16, f17_32, f33_48, f49_63;
456
457 __ bind(&f9_16);
458 __ movdbl(xmm0, Operand(src, 0));
459 __ movdbl(xmm1, Operand(src, count, times_1, -8));
460 __ movdbl(Operand(dst, 0), xmm0);
461 __ movdbl(Operand(dst, count, times_1, -8), xmm1);
462 MemMoveEmitPopAndReturn(&masm);
463
464 __ bind(&f17_32);
465 __ movdqu(xmm0, Operand(src, 0));
466 __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
467 __ movdqu(Operand(dst, 0x00), xmm0);
468 __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
469 MemMoveEmitPopAndReturn(&masm);
470
471 __ bind(&f33_48);
472 __ movdqu(xmm0, Operand(src, 0x00));
473 __ movdqu(xmm1, Operand(src, 0x10));
474 __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
475 __ movdqu(Operand(dst, 0x00), xmm0);
476 __ movdqu(Operand(dst, 0x10), xmm1);
477 __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
478 MemMoveEmitPopAndReturn(&masm);
479
480 __ bind(&f49_63);
481 __ movdqu(xmm0, Operand(src, 0x00));
482 __ movdqu(xmm1, Operand(src, 0x10));
483 __ movdqu(xmm2, Operand(src, 0x20));
484 __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
485 __ movdqu(Operand(dst, 0x00), xmm0);
486 __ movdqu(Operand(dst, 0x10), xmm1);
487 __ movdqu(Operand(dst, 0x20), xmm2);
488 __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
489 MemMoveEmitPopAndReturn(&masm);
490
491 medium_handlers = new size_t[4];
492 medium_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f9_16.pos();
493 medium_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f17_32.pos();
494 medium_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f33_48.pos();
495 medium_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f49_63.pos();
496
497 __ bind(&medium_size); // Entry point into this block.
498 __ mov(eax, count);
499 __ dec(eax);
500 __ shr(eax, 4);
501 if (FLAG_debug_code) {
502 Label ok;
503 __ cmp(eax, 3);
504 __ j(below_equal, &ok);
505 __ int3();
506 __ bind(&ok);
507 }
508 __ mov(eax, Operand(eax, times_4,
509 reinterpret_cast<intptr_t>(medium_handlers)));
510 __ jmp(eax);
511 }
512 {
513 // Specialized copiers for copy_size <= 8 bytes.
514 Label f0, f1, f2, f3, f4, f5_8;
515 __ bind(&f0);
516 MemMoveEmitPopAndReturn(&masm);
517
518 __ bind(&f1);
519 __ mov_b(eax, Operand(src, 0));
520 __ mov_b(Operand(dst, 0), eax);
521 MemMoveEmitPopAndReturn(&masm);
522
523 __ bind(&f2);
524 __ mov_w(eax, Operand(src, 0));
525 __ mov_w(Operand(dst, 0), eax);
526 MemMoveEmitPopAndReturn(&masm);
527
528 __ bind(&f3);
529 __ mov_w(eax, Operand(src, 0));
530 __ mov_b(edx, Operand(src, 2));
531 __ mov_w(Operand(dst, 0), eax);
532 __ mov_b(Operand(dst, 2), edx);
533 MemMoveEmitPopAndReturn(&masm);
534
535 __ bind(&f4);
536 __ mov(eax, Operand(src, 0));
537 __ mov(Operand(dst, 0), eax);
538 MemMoveEmitPopAndReturn(&masm);
539
540 __ bind(&f5_8);
541 __ mov(eax, Operand(src, 0));
542 __ mov(edx, Operand(src, count, times_1, -4));
543 __ mov(Operand(dst, 0), eax);
544 __ mov(Operand(dst, count, times_1, -4), edx);
545 MemMoveEmitPopAndReturn(&masm);
546
547 small_handlers = new size_t[9];
548 small_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f0.pos();
549 small_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f1.pos();
550 small_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f2.pos();
551 small_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f3.pos();
552 small_handlers[4] = reinterpret_cast<intptr_t>(buffer) + f4.pos();
553 small_handlers[5] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
554 small_handlers[6] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
555 small_handlers[7] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
556 small_handlers[8] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
557
558 __ bind(&small_size); // Entry point into this block.
559 if (FLAG_debug_code) {
560 Label ok;
561 __ cmp(count, 8);
562 __ j(below_equal, &ok);
563 __ int3();
564 __ bind(&ok);
565 }
566 __ mov(eax, Operand(count, times_4,
567 reinterpret_cast<intptr_t>(small_handlers)));
568 __ jmp(eax);
569 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000570 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000571 // No SSE2.
572 Label forward;
573 __ cmp(count, 0);
574 __ j(equal, &pop_and_return);
575 __ cmp(dst, src);
576 __ j(above, &backward);
577 __ jmp(&forward);
578 {
579 // Simple forward copier.
580 Label forward_loop_1byte, forward_loop_4byte;
581 __ bind(&forward_loop_4byte);
582 __ mov(eax, Operand(src, 0));
583 __ sub(count, Immediate(4));
584 __ add(src, Immediate(4));
585 __ mov(Operand(dst, 0), eax);
586 __ add(dst, Immediate(4));
587 __ bind(&forward); // Entry point.
588 __ cmp(count, 3);
589 __ j(above, &forward_loop_4byte);
590 __ bind(&forward_loop_1byte);
591 __ cmp(count, 0);
592 __ j(below_equal, &pop_and_return);
593 __ mov_b(eax, Operand(src, 0));
594 __ dec(count);
595 __ inc(src);
596 __ mov_b(Operand(dst, 0), eax);
597 __ inc(dst);
598 __ jmp(&forward_loop_1byte);
599 }
600 {
601 // Simple backward copier.
602 Label backward_loop_1byte, backward_loop_4byte, entry_shortcut;
603 __ bind(&backward);
604 __ add(src, count);
605 __ add(dst, count);
606 __ cmp(count, 3);
607 __ j(below_equal, &entry_shortcut);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000608
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000609 __ bind(&backward_loop_4byte);
610 __ sub(src, Immediate(4));
611 __ sub(count, Immediate(4));
612 __ mov(eax, Operand(src, 0));
613 __ sub(dst, Immediate(4));
614 __ mov(Operand(dst, 0), eax);
615 __ cmp(count, 3);
616 __ j(above, &backward_loop_4byte);
617 __ bind(&backward_loop_1byte);
618 __ cmp(count, 0);
619 __ j(below_equal, &pop_and_return);
620 __ bind(&entry_shortcut);
621 __ dec(src);
622 __ dec(count);
623 __ mov_b(eax, Operand(src, 0));
624 __ dec(dst);
625 __ mov_b(Operand(dst, 0), eax);
626 __ jmp(&backward_loop_1byte);
627 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000628 }
629
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000630 __ bind(&pop_and_return);
631 MemMoveEmitPopAndReturn(&masm);
632
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000633 CodeDesc desc;
634 masm.GetCode(&desc);
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000635 ASSERT(!RelocInfo::RequiresRelocation(desc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000636 CPU::FlushICache(buffer, actual_size);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000637 OS::ProtectCode(buffer, actual_size);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000638 // TODO(jkummerow): It would be nice to register this code creation event
639 // with the PROFILE / GDBJIT system.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000640 return FUNCTION_CAST<OS::MemMoveFunction>(buffer);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000641}
642
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000643
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000644#undef __
645
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000646// -------------------------------------------------------------------------
647// Code generators
648
649#define __ ACCESS_MASM(masm)
650
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000651
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000652void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000653 MacroAssembler* masm, AllocationSiteMode mode,
654 Label* allocation_site_info_found) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000655 // ----------- S t a t e -------------
656 // -- eax : value
657 // -- ebx : target map
658 // -- ecx : key
659 // -- edx : receiver
660 // -- esp[0] : return address
661 // -----------------------------------
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000662 if (mode == TRACK_ALLOCATION_SITE) {
663 ASSERT(allocation_site_info_found != NULL);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000664 __ TestJSArrayForAllocationSiteInfo(edx, edi);
665 __ j(equal, allocation_site_info_found);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000666 }
667
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000668 // Set transitioned map.
669 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
670 __ RecordWriteField(edx,
671 HeapObject::kMapOffset,
672 ebx,
673 edi,
674 kDontSaveFPRegs,
675 EMIT_REMEMBERED_SET,
676 OMIT_SMI_CHECK);
677}
678
679
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000680void ElementsTransitionGenerator::GenerateSmiToDouble(
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000681 MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000682 // ----------- S t a t e -------------
683 // -- eax : value
684 // -- ebx : target map
685 // -- ecx : key
686 // -- edx : receiver
687 // -- esp[0] : return address
688 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000689 Label loop, entry, convert_hole, gc_required, only_change_map;
690
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000691 if (mode == TRACK_ALLOCATION_SITE) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000692 __ TestJSArrayForAllocationSiteInfo(edx, edi);
693 __ j(equal, fail);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000694 }
695
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000696 // Check for empty arrays, which only require a map transition and no changes
697 // to the backing store.
698 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
699 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
700 __ j(equal, &only_change_map);
701
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000702 __ push(eax);
703 __ push(ebx);
704
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000705 __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
706
707 // Allocate new FixedDoubleArray.
708 // edx: receiver
709 // edi: length of source FixedArray (smi-tagged)
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000710 AllocationFlags flags =
711 static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000712 __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi,
713 REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000714
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000715 // eax: destination FixedDoubleArray
716 // edi: number of elements
717 // edx: receiver
718 __ mov(FieldOperand(eax, HeapObject::kMapOffset),
719 Immediate(masm->isolate()->factory()->fixed_double_array_map()));
720 __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
721 __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
722 // Replace receiver's backing store with newly created FixedDoubleArray.
723 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
724 __ mov(ebx, eax);
725 __ RecordWriteField(edx,
726 JSObject::kElementsOffset,
727 ebx,
728 edi,
729 kDontSaveFPRegs,
730 EMIT_REMEMBERED_SET,
731 OMIT_SMI_CHECK);
732
733 __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
734
735 // Prepare for conversion loop.
736 ExternalReference canonical_the_hole_nan_reference =
737 ExternalReference::address_of_the_hole_nan();
738 XMMRegister the_hole_nan = xmm1;
739 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000740 CpuFeatureScope use_sse2(masm, SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000741 __ movdbl(the_hole_nan,
742 Operand::StaticVariable(canonical_the_hole_nan_reference));
743 }
744 __ jmp(&entry);
745
746 // Call into runtime if GC is required.
747 __ bind(&gc_required);
748 // Restore registers before jumping into runtime.
749 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
750 __ pop(ebx);
751 __ pop(eax);
752 __ jmp(fail);
753
754 // Convert and copy elements
755 // esi: source FixedArray
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 __ bind(&loop);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000757 __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
758 // ebx: current element from source
759 // edi: index of current element
760 __ JumpIfNotSmi(ebx, &convert_hole);
761
762 // Normal smi, convert it to double and store.
763 __ SmiUntag(ebx);
764 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000765 CpuFeatureScope fscope(masm, SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 __ cvtsi2sd(xmm0, ebx);
767 __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
768 xmm0);
769 } else {
770 __ push(ebx);
771 __ fild_s(Operand(esp, 0));
772 __ pop(ebx);
773 __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
774 }
775 __ jmp(&entry);
776
777 // Found hole, store hole_nan_as_double instead.
778 __ bind(&convert_hole);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000779
780 if (FLAG_debug_code) {
781 __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
782 __ Assert(equal, "object found in smi-only array");
783 }
784
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000785 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000786 CpuFeatureScope use_sse2(masm, SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000787 __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
788 the_hole_nan);
789 } else {
790 __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
791 __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
792 }
793
794 __ bind(&entry);
erik.corry@gmail.combecbc522011-10-28 07:45:20 +0000795 __ sub(edi, Immediate(Smi::FromInt(1)));
796 __ j(not_sign, &loop);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797
798 __ pop(ebx);
799 __ pop(eax);
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000800
801 // Restore esi.
802 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
803
804 __ bind(&only_change_map);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000805 // eax: value
806 // ebx: target map
807 // Set transitioned map.
808 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
809 __ RecordWriteField(edx,
810 HeapObject::kMapOffset,
811 ebx,
812 edi,
813 kDontSaveFPRegs,
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000814 OMIT_REMEMBERED_SET,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000815 OMIT_SMI_CHECK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000816}
817
818
819void ElementsTransitionGenerator::GenerateDoubleToObject(
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000820 MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000821 // ----------- S t a t e -------------
822 // -- eax : value
823 // -- ebx : target map
824 // -- ecx : key
825 // -- edx : receiver
826 // -- esp[0] : return address
827 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000828 Label loop, entry, convert_hole, gc_required, only_change_map, success;
829
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000830 if (mode == TRACK_ALLOCATION_SITE) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000831 __ TestJSArrayForAllocationSiteInfo(edx, edi);
832 __ j(equal, fail);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000833 }
834
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000835 // Check for empty arrays, which only require a map transition and no changes
836 // to the backing store.
837 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
838 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
839 __ j(equal, &only_change_map);
840
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000841 __ push(eax);
842 __ push(edx);
843 __ push(ebx);
844
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000845 __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
846
847 // Allocate new FixedArray.
848 // ebx: length of source FixedDoubleArray (smi-tagged)
849 __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000850 __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000851
852 // eax: destination FixedArray
853 // ebx: number of elements
854 __ mov(FieldOperand(eax, HeapObject::kMapOffset),
855 Immediate(masm->isolate()->factory()->fixed_array_map()));
856 __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
857 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
858
859 __ jmp(&entry);
860
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000861 // ebx: target map
862 // edx: receiver
863 // Set transitioned map.
864 __ bind(&only_change_map);
865 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
866 __ RecordWriteField(edx,
867 HeapObject::kMapOffset,
868 ebx,
869 edi,
870 kDontSaveFPRegs,
871 OMIT_REMEMBERED_SET,
872 OMIT_SMI_CHECK);
873 __ jmp(&success);
874
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000875 // Call into runtime if GC is required.
876 __ bind(&gc_required);
877 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
878 __ pop(ebx);
879 __ pop(edx);
880 __ pop(eax);
881 __ jmp(fail);
882
883 // Box doubles into heap numbers.
884 // edi: source FixedDoubleArray
885 // eax: destination FixedArray
886 __ bind(&loop);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000887 // ebx: index of current element (smi-tagged)
888 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
889 __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
890 __ j(equal, &convert_hole);
891
892 // Non-hole double, copy value into a heap number.
893 __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
894 // edx: new heap number
895 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000896 CpuFeatureScope fscope(masm, SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000897 __ movdbl(xmm0,
898 FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
899 __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
900 } else {
901 __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
902 __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
903 __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
904 __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
905 }
906 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
907 __ mov(esi, ebx);
908 __ RecordWriteArray(eax,
909 edx,
910 esi,
911 kDontSaveFPRegs,
912 EMIT_REMEMBERED_SET,
913 OMIT_SMI_CHECK);
914 __ jmp(&entry, Label::kNear);
915
916 // Replace the-hole NaN with the-hole pointer.
917 __ bind(&convert_hole);
918 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
919 masm->isolate()->factory()->the_hole_value());
920
921 __ bind(&entry);
erik.corry@gmail.combecbc522011-10-28 07:45:20 +0000922 __ sub(ebx, Immediate(Smi::FromInt(1)));
923 __ j(not_sign, &loop);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000924
925 __ pop(ebx);
926 __ pop(edx);
927 // ebx: target map
928 // edx: receiver
929 // Set transitioned map.
930 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
931 __ RecordWriteField(edx,
932 HeapObject::kMapOffset,
933 ebx,
934 edi,
935 kDontSaveFPRegs,
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000936 OMIT_REMEMBERED_SET,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000937 OMIT_SMI_CHECK);
938 // Replace receiver's backing store with newly created and filled FixedArray.
939 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
940 __ RecordWriteField(edx,
941 JSObject::kElementsOffset,
942 eax,
943 edi,
944 kDontSaveFPRegs,
945 EMIT_REMEMBERED_SET,
946 OMIT_SMI_CHECK);
947
948 // Restore registers.
949 __ pop(eax);
950 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000951
952 __ bind(&success);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000953}
954
erikcorry0ad885c2011-11-21 13:51:57 +0000955
956void StringCharLoadGenerator::Generate(MacroAssembler* masm,
957 Factory* factory,
958 Register string,
959 Register index,
960 Register result,
961 Label* call_runtime) {
962 // Fetch the instance type of the receiver into result register.
963 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
964 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
965
966 // We need special handling for indirect strings.
967 Label check_sequential;
968 __ test(result, Immediate(kIsIndirectStringMask));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000969 __ j(zero, &check_sequential, Label::kNear);
erikcorry0ad885c2011-11-21 13:51:57 +0000970
971 // Dispatch on the indirect string shape: slice or cons.
972 Label cons_string;
973 __ test(result, Immediate(kSlicedNotConsMask));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000974 __ j(zero, &cons_string, Label::kNear);
erikcorry0ad885c2011-11-21 13:51:57 +0000975
976 // Handle slices.
977 Label indirect_string_loaded;
978 __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
979 __ SmiUntag(result);
980 __ add(index, result);
981 __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000982 __ jmp(&indirect_string_loaded, Label::kNear);
erikcorry0ad885c2011-11-21 13:51:57 +0000983
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000984 // Handle cons strings.
erikcorry0ad885c2011-11-21 13:51:57 +0000985 // Check whether the right hand side is the empty string (i.e. if
986 // this is really a flat string in a cons string). If that is not
987 // the case we would rather go to the runtime system now to flatten
988 // the string.
989 __ bind(&cons_string);
990 __ cmp(FieldOperand(string, ConsString::kSecondOffset),
991 Immediate(factory->empty_string()));
992 __ j(not_equal, call_runtime);
993 __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
994
995 __ bind(&indirect_string_loaded);
996 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
997 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
998
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000999 // Distinguish sequential and external strings. Only these two string
1000 // representations can reach here (slices and flat cons strings have been
1001 // reduced to the underlying sequential or external string).
1002 Label seq_string;
erikcorry0ad885c2011-11-21 13:51:57 +00001003 __ bind(&check_sequential);
1004 STATIC_ASSERT(kSeqStringTag == 0);
1005 __ test(result, Immediate(kStringRepresentationMask));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001006 __ j(zero, &seq_string, Label::kNear);
1007
1008 // Handle external strings.
1009 Label ascii_external, done;
1010 if (FLAG_debug_code) {
1011 // Assert that we do not have a cons or slice (indirect strings) here.
1012 // Sequential strings have already been ruled out.
1013 __ test(result, Immediate(kIsIndirectStringMask));
1014 __ Assert(zero, "external string expected, but not found");
1015 }
1016 // Rule out short external strings.
1017 STATIC_CHECK(kShortExternalStringTag != 0);
1018 __ test_b(result, kShortExternalStringMask);
1019 __ j(not_zero, call_runtime);
1020 // Check encoding.
1021 STATIC_ASSERT(kTwoByteStringTag == 0);
1022 __ test_b(result, kStringEncodingMask);
1023 __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
1024 __ j(not_equal, &ascii_external, Label::kNear);
1025 // Two-byte string.
1026 __ movzx_w(result, Operand(result, index, times_2, 0));
1027 __ jmp(&done, Label::kNear);
1028 __ bind(&ascii_external);
1029 // Ascii string.
1030 __ movzx_b(result, Operand(result, index, times_1, 0));
1031 __ jmp(&done, Label::kNear);
erikcorry0ad885c2011-11-21 13:51:57 +00001032
1033 // Dispatch on the encoding: ASCII or two-byte.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001034 Label ascii;
1035 __ bind(&seq_string);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001036 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
erikcorry0ad885c2011-11-21 13:51:57 +00001037 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
1038 __ test(result, Immediate(kStringEncodingMask));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001039 __ j(not_zero, &ascii, Label::kNear);
erikcorry0ad885c2011-11-21 13:51:57 +00001040
1041 // Two-byte string.
1042 // Load the two-byte character code into the result register.
erikcorry0ad885c2011-11-21 13:51:57 +00001043 __ movzx_w(result, FieldOperand(string,
1044 index,
1045 times_2,
1046 SeqTwoByteString::kHeaderSize));
1047 __ jmp(&done, Label::kNear);
1048
1049 // Ascii string.
1050 // Load the byte into the result register.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001051 __ bind(&ascii);
erikcorry0ad885c2011-11-21 13:51:57 +00001052 __ movzx_b(result, FieldOperand(string,
1053 index,
1054 times_1,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001055 SeqOneByteString::kHeaderSize));
erikcorry0ad885c2011-11-21 13:51:57 +00001056 __ bind(&done);
1057}
1058
danno@chromium.org1f34ad32012-11-26 14:53:56 +00001059
1060static Operand ExpConstant(int index) {
1061 return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
1062}
1063
1064
1065void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
1066 XMMRegister input,
1067 XMMRegister result,
1068 XMMRegister double_scratch,
1069 Register temp1,
1070 Register temp2) {
1071 ASSERT(!input.is(double_scratch));
1072 ASSERT(!input.is(result));
1073 ASSERT(!result.is(double_scratch));
1074 ASSERT(!temp1.is(temp2));
1075 ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
1076
1077 Label done;
1078
1079 __ movdbl(double_scratch, ExpConstant(0));
1080 __ xorpd(result, result);
1081 __ ucomisd(double_scratch, input);
1082 __ j(above_equal, &done);
1083 __ ucomisd(input, ExpConstant(1));
1084 __ movdbl(result, ExpConstant(2));
1085 __ j(above_equal, &done);
1086 __ movdbl(double_scratch, ExpConstant(3));
1087 __ movdbl(result, ExpConstant(4));
1088 __ mulsd(double_scratch, input);
1089 __ addsd(double_scratch, result);
1090 __ movd(temp2, double_scratch);
1091 __ subsd(double_scratch, result);
1092 __ movdbl(result, ExpConstant(6));
1093 __ mulsd(double_scratch, ExpConstant(5));
1094 __ subsd(double_scratch, input);
1095 __ subsd(result, double_scratch);
1096 __ movsd(input, double_scratch);
1097 __ mulsd(input, double_scratch);
1098 __ mulsd(result, input);
1099 __ mov(temp1, temp2);
1100 __ mulsd(result, ExpConstant(7));
1101 __ subsd(result, double_scratch);
1102 __ add(temp1, Immediate(0x1ff800));
1103 __ addsd(result, ExpConstant(8));
1104 __ and_(temp2, Immediate(0x7ff));
1105 __ shr(temp1, 11);
1106 __ shl(temp1, 20);
1107 __ movd(input, temp1);
1108 __ pshufd(input, input, static_cast<uint8_t>(0xe1)); // Order: 11 10 00 01
1109 __ movdbl(double_scratch, Operand::StaticArray(
1110 temp2, times_8, ExternalReference::math_exp_log_table()));
1111 __ por(input, double_scratch);
1112 __ mulsd(result, input);
1113 __ bind(&done);
1114}
1115
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001116#undef __
1117
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001118static const int kNoCodeAgeSequenceLength = 5;
1119
1120static byte* GetNoCodeAgeSequence(uint32_t* length) {
1121 static bool initialized = false;
1122 static byte sequence[kNoCodeAgeSequenceLength];
1123 *length = kNoCodeAgeSequenceLength;
1124 if (!initialized) {
1125 // The sequence of instructions that is patched out for aging code is the
1126 // following boilerplate stack-building prologue that is found both in
1127 // FUNCTION and OPTIMIZED_FUNCTION code:
1128 CodePatcher patcher(sequence, kNoCodeAgeSequenceLength);
1129 patcher.masm()->push(ebp);
1130 patcher.masm()->mov(ebp, esp);
1131 patcher.masm()->push(esi);
1132 patcher.masm()->push(edi);
1133 initialized = true;
1134 }
1135 return sequence;
1136}
1137
1138
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001139bool Code::IsYoungSequence(byte* sequence) {
1140 uint32_t young_length;
1141 byte* young_sequence = GetNoCodeAgeSequence(&young_length);
1142 bool result = (!memcmp(sequence, young_sequence, young_length));
1143 ASSERT(result || *sequence == kCallOpcode);
1144 return result;
1145}
1146
1147
1148void Code::GetCodeAgeAndParity(byte* sequence, Age* age,
1149 MarkingParity* parity) {
1150 if (IsYoungSequence(sequence)) {
1151 *age = kNoAge;
1152 *parity = NO_MARKING_PARITY;
1153 } else {
1154 sequence++; // Skip the kCallOpcode byte
1155 Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
1156 Assembler::kCallTargetAddressOffset;
1157 Code* stub = GetCodeFromTargetAddress(target_address);
1158 GetCodeAgeAndParity(stub, age, parity);
1159 }
1160}
1161
1162
1163void Code::PatchPlatformCodeAge(byte* sequence,
1164 Code::Age age,
1165 MarkingParity parity) {
1166 uint32_t young_length;
1167 byte* young_sequence = GetNoCodeAgeSequence(&young_length);
1168 if (age == kNoAge) {
danno@chromium.orgc99cd482013-03-21 15:26:42 +00001169 CopyBytes(sequence, young_sequence, young_length);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001170 CPU::FlushICache(sequence, young_length);
1171 } else {
1172 Code* stub = GetCodeAgeStub(age, parity);
1173 CodePatcher patcher(sequence, young_length);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001174 patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001175 }
1176}
1177
1178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001180
1181#endif // V8_TARGET_ARCH_IA32