blob: ea619103228c43bab8a695b0cfb8a51a6e68fd88 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_IA32)
31
Ben Murdoch8b112d22011-06-08 16:22:53 +010032#include "codegen.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010033#include "heap.h"
34#include "macro-assembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035
36namespace v8 {
37namespace internal {
38
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010039
40// -------------------------------------------------------------------------
41// Platform-specific RuntimeCallHelper functions.
42
Ben Murdochb0fe1622011-05-05 13:52:32 +010043void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010044 masm->EnterFrame(StackFrame::INTERNAL);
45 ASSERT(!masm->has_frame());
46 masm->set_has_frame(true);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010047}
48
49
Ben Murdochb0fe1622011-05-05 13:52:32 +010050void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010051 masm->LeaveFrame(StackFrame::INTERNAL);
52 ASSERT(masm->has_frame());
53 masm->set_has_frame(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010054}
55
56
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010057#define __ masm.
58
Ben Murdoch3ef787d2012-04-12 10:51:47 +010059
60UnaryMathFunction 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(desc.reloc_size == 0);
98
99 CPU::FlushICache(buffer, actual_size);
100 OS::ProtectCode(buffer, actual_size);
101 return FUNCTION_CAST<UnaryMathFunction>(buffer);
102}
103
104
105UnaryMathFunction CreateSqrtFunction() {
106 size_t actual_size;
107 // Allocate buffer in executable space.
108 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
109 &actual_size,
110 true));
111 // If SSE2 is not available, we can use libc's implementation to ensure
112 // consistency since code by fullcodegen's calls into runtime in that case.
113 if (buffer == NULL || !CpuFeatures::IsSupported(SSE2)) return &sqrt;
114 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
115 // esp[1 * kPointerSize]: raw double input
116 // esp[0 * kPointerSize]: return address
117 // Move double input into registers.
118 {
119 CpuFeatures::Scope use_sse2(SSE2);
120 __ movdbl(xmm0, Operand(esp, 1 * kPointerSize));
121 __ sqrtsd(xmm0, xmm0);
122 __ movdbl(Operand(esp, 1 * kPointerSize), xmm0);
123 // Load result into floating point register as return value.
124 __ fld_d(Operand(esp, 1 * kPointerSize));
125 __ Ret();
126 }
127
128 CodeDesc desc;
129 masm.GetCode(&desc);
130 ASSERT(desc.reloc_size == 0);
131
132 CPU::FlushICache(buffer, actual_size);
133 OS::ProtectCode(buffer, actual_size);
134 return FUNCTION_CAST<UnaryMathFunction>(buffer);
135}
136
137
Ben Murdochb0fe1622011-05-05 13:52:32 +0100138static void MemCopyWrapper(void* dest, const void* src, size_t size) {
139 memcpy(dest, src, size);
140}
141
142
Ben Murdoch8b112d22011-06-08 16:22:53 +0100143OS::MemCopyFunction CreateMemCopyFunction() {
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 (buffer == NULL) return &MemCopyWrapper;
150 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100151
152 // Generated code is put into a fixed, unmovable, buffer, and not into
153 // the V8 heap. We can't, and don't, refer to any relocatable addresses
154 // (e.g. the JavaScript nan-object).
155
156 // 32-bit C declaration function calls pass arguments on stack.
157
158 // Stack layout:
159 // esp[12]: Third argument, size.
160 // esp[8]: Second argument, source pointer.
161 // esp[4]: First argument, destination pointer.
162 // esp[0]: return address
163
164 const int kDestinationOffset = 1 * kPointerSize;
165 const int kSourceOffset = 2 * kPointerSize;
166 const int kSizeOffset = 3 * kPointerSize;
167
168 int stack_offset = 0; // Update if we change the stack height.
169
170 if (FLAG_debug_code) {
171 __ cmp(Operand(esp, kSizeOffset + stack_offset),
Ben Murdoch8b112d22011-06-08 16:22:53 +0100172 Immediate(OS::kMinComplexMemCopy));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100173 Label ok;
174 __ j(greater_equal, &ok);
175 __ int3();
176 __ bind(&ok);
177 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100178 if (CpuFeatures::IsSupported(SSE2)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100179 CpuFeatures::Scope enable(SSE2);
180 __ push(edi);
181 __ push(esi);
182 stack_offset += 2 * kPointerSize;
183 Register dst = edi;
184 Register src = esi;
185 Register count = ecx;
186 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
187 __ mov(src, Operand(esp, stack_offset + kSourceOffset));
188 __ mov(count, Operand(esp, stack_offset + kSizeOffset));
189
190
191 __ movdqu(xmm0, Operand(src, 0));
192 __ movdqu(Operand(dst, 0), xmm0);
193 __ mov(edx, dst);
194 __ and_(edx, 0xF);
195 __ neg(edx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100196 __ add(edx, Immediate(16));
197 __ add(dst, edx);
198 __ add(src, edx);
199 __ sub(count, edx);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100200
201 // edi is now aligned. Check if esi is also aligned.
202 Label unaligned_source;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100203 __ test(src, Immediate(0x0F));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100204 __ j(not_zero, &unaligned_source);
205 {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100206 // Copy loop for aligned source and destination.
207 __ mov(edx, count);
208 Register loop_count = ecx;
209 Register count = edx;
210 __ shr(loop_count, 5);
211 {
212 // Main copy loop.
213 Label loop;
214 __ bind(&loop);
215 __ prefetch(Operand(src, 0x20), 1);
216 __ movdqa(xmm0, Operand(src, 0x00));
217 __ movdqa(xmm1, Operand(src, 0x10));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100218 __ add(src, Immediate(0x20));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100219
220 __ movdqa(Operand(dst, 0x00), xmm0);
221 __ movdqa(Operand(dst, 0x10), xmm1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100222 __ add(dst, Immediate(0x20));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100223
224 __ dec(loop_count);
225 __ j(not_zero, &loop);
226 }
227
228 // At most 31 bytes to copy.
229 Label move_less_16;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 __ test(count, Immediate(0x10));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100231 __ j(zero, &move_less_16);
232 __ movdqa(xmm0, Operand(src, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100233 __ add(src, Immediate(0x10));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100234 __ movdqa(Operand(dst, 0), xmm0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100235 __ add(dst, Immediate(0x10));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100236 __ bind(&move_less_16);
237
238 // At most 15 bytes to copy. Copy 16 bytes at end of string.
239 __ and_(count, 0xF);
240 __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
241 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
242
Ben Murdochb0fe1622011-05-05 13:52:32 +0100243 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100244 __ pop(esi);
245 __ pop(edi);
246 __ ret(0);
247 }
248 __ Align(16);
249 {
250 // Copy loop for unaligned source and aligned destination.
251 // If source is not aligned, we can't read it as efficiently.
252 __ bind(&unaligned_source);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100253 __ mov(edx, ecx);
254 Register loop_count = ecx;
255 Register count = edx;
256 __ shr(loop_count, 5);
257 {
258 // Main copy loop
259 Label loop;
260 __ bind(&loop);
261 __ prefetch(Operand(src, 0x20), 1);
262 __ movdqu(xmm0, Operand(src, 0x00));
263 __ movdqu(xmm1, Operand(src, 0x10));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100264 __ add(src, Immediate(0x20));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100265
266 __ movdqa(Operand(dst, 0x00), xmm0);
267 __ movdqa(Operand(dst, 0x10), xmm1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100268 __ add(dst, Immediate(0x20));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100269
270 __ dec(loop_count);
271 __ j(not_zero, &loop);
272 }
273
274 // At most 31 bytes to copy.
275 Label move_less_16;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100276 __ test(count, Immediate(0x10));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100277 __ j(zero, &move_less_16);
278 __ movdqu(xmm0, Operand(src, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100279 __ add(src, Immediate(0x10));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100280 __ movdqa(Operand(dst, 0), xmm0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100281 __ add(dst, Immediate(0x10));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100282 __ bind(&move_less_16);
283
284 // At most 15 bytes to copy. Copy 16 bytes at end of string.
285 __ and_(count, 0x0F);
286 __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
287 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
288
Ben Murdochb0fe1622011-05-05 13:52:32 +0100289 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100290 __ pop(esi);
291 __ pop(edi);
292 __ ret(0);
293 }
294
295 } else {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100296 // SSE2 not supported. Unlikely to happen in practice.
297 __ push(edi);
298 __ push(esi);
299 stack_offset += 2 * kPointerSize;
300 __ cld();
301 Register dst = edi;
302 Register src = esi;
303 Register count = ecx;
304 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
305 __ mov(src, Operand(esp, stack_offset + kSourceOffset));
306 __ mov(count, Operand(esp, stack_offset + kSizeOffset));
307
308 // Copy the first word.
309 __ mov(eax, Operand(src, 0));
310 __ mov(Operand(dst, 0), eax);
311
312 // Increment src,dstso that dst is aligned.
313 __ mov(edx, dst);
314 __ and_(edx, 0x03);
315 __ neg(edx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100316 __ add(edx, Immediate(4)); // edx = 4 - (dst & 3)
317 __ add(dst, edx);
318 __ add(src, edx);
319 __ sub(count, edx);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100320 // edi is now aligned, ecx holds number of remaning bytes to copy.
321
322 __ mov(edx, count);
323 count = edx;
324 __ shr(ecx, 2); // Make word count instead of byte count.
325 __ rep_movs();
326
327 // At most 3 bytes left to copy. Copy 4 bytes at end of string.
328 __ and_(count, 3);
329 __ mov(eax, Operand(src, count, times_1, -4));
330 __ mov(Operand(dst, count, times_1, -4), eax);
331
Ben Murdochb0fe1622011-05-05 13:52:32 +0100332 __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100333 __ pop(esi);
334 __ pop(edi);
335 __ ret(0);
336 }
337
338 CodeDesc desc;
339 masm.GetCode(&desc);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100340 ASSERT(desc.reloc_size == 0);
341
Ben Murdoch8b112d22011-06-08 16:22:53 +0100342 CPU::FlushICache(buffer, actual_size);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000343 OS::ProtectCode(buffer, actual_size);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100344 return FUNCTION_CAST<OS::MemCopyFunction>(buffer);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100345}
346
347#undef __
348
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100349// -------------------------------------------------------------------------
350// Code generators
351
352#define __ ACCESS_MASM(masm)
353
354void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
355 MacroAssembler* masm) {
356 // ----------- S t a t e -------------
357 // -- eax : value
358 // -- ebx : target map
359 // -- ecx : key
360 // -- edx : receiver
361 // -- esp[0] : return address
362 // -----------------------------------
363 // Set transitioned map.
364 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
365 __ RecordWriteField(edx,
366 HeapObject::kMapOffset,
367 ebx,
368 edi,
369 kDontSaveFPRegs,
370 EMIT_REMEMBERED_SET,
371 OMIT_SMI_CHECK);
372}
373
374
375void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
376 MacroAssembler* masm, Label* fail) {
377 // ----------- S t a t e -------------
378 // -- eax : value
379 // -- ebx : target map
380 // -- ecx : key
381 // -- edx : receiver
382 // -- esp[0] : return address
383 // -----------------------------------
384 Label loop, entry, convert_hole, gc_required, only_change_map;
385
386 // Check for empty arrays, which only require a map transition and no changes
387 // to the backing store.
388 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
389 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
390 __ j(equal, &only_change_map);
391
392 __ push(eax);
393 __ push(ebx);
394
395 __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
396
397 // Allocate new FixedDoubleArray.
398 // edx: receiver
399 // edi: length of source FixedArray (smi-tagged)
400 __ lea(esi, Operand(edi, times_4, FixedDoubleArray::kHeaderSize));
401 __ AllocateInNewSpace(esi, eax, ebx, no_reg, &gc_required, TAG_OBJECT);
402
403 // eax: destination FixedDoubleArray
404 // edi: number of elements
405 // edx: receiver
406 __ mov(FieldOperand(eax, HeapObject::kMapOffset),
407 Immediate(masm->isolate()->factory()->fixed_double_array_map()));
408 __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
409 __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
410 // Replace receiver's backing store with newly created FixedDoubleArray.
411 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
412 __ mov(ebx, eax);
413 __ RecordWriteField(edx,
414 JSObject::kElementsOffset,
415 ebx,
416 edi,
417 kDontSaveFPRegs,
418 EMIT_REMEMBERED_SET,
419 OMIT_SMI_CHECK);
420
421 __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
422
423 // Prepare for conversion loop.
424 ExternalReference canonical_the_hole_nan_reference =
425 ExternalReference::address_of_the_hole_nan();
426 XMMRegister the_hole_nan = xmm1;
427 if (CpuFeatures::IsSupported(SSE2)) {
428 CpuFeatures::Scope use_sse2(SSE2);
429 __ movdbl(the_hole_nan,
430 Operand::StaticVariable(canonical_the_hole_nan_reference));
431 }
432 __ jmp(&entry);
433
434 // Call into runtime if GC is required.
435 __ bind(&gc_required);
436 // Restore registers before jumping into runtime.
437 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
438 __ pop(ebx);
439 __ pop(eax);
440 __ jmp(fail);
441
442 // Convert and copy elements
443 // esi: source FixedArray
444 __ bind(&loop);
445 __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
446 // ebx: current element from source
447 // edi: index of current element
448 __ JumpIfNotSmi(ebx, &convert_hole);
449
450 // Normal smi, convert it to double and store.
451 __ SmiUntag(ebx);
452 if (CpuFeatures::IsSupported(SSE2)) {
453 CpuFeatures::Scope fscope(SSE2);
454 __ cvtsi2sd(xmm0, ebx);
455 __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
456 xmm0);
457 } else {
458 __ push(ebx);
459 __ fild_s(Operand(esp, 0));
460 __ pop(ebx);
461 __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
462 }
463 __ jmp(&entry);
464
465 // Found hole, store hole_nan_as_double instead.
466 __ bind(&convert_hole);
467
468 if (FLAG_debug_code) {
469 __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
470 __ Assert(equal, "object found in smi-only array");
471 }
472
473 if (CpuFeatures::IsSupported(SSE2)) {
474 CpuFeatures::Scope use_sse2(SSE2);
475 __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
476 the_hole_nan);
477 } else {
478 __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
479 __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
480 }
481
482 __ bind(&entry);
483 __ sub(edi, Immediate(Smi::FromInt(1)));
484 __ j(not_sign, &loop);
485
486 __ pop(ebx);
487 __ pop(eax);
488
489 // Restore esi.
490 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
491
492 __ bind(&only_change_map);
493 // eax: value
494 // ebx: target map
495 // Set transitioned map.
496 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
497 __ RecordWriteField(edx,
498 HeapObject::kMapOffset,
499 ebx,
500 edi,
501 kDontSaveFPRegs,
502 OMIT_REMEMBERED_SET,
503 OMIT_SMI_CHECK);
504}
505
506
507void ElementsTransitionGenerator::GenerateDoubleToObject(
508 MacroAssembler* masm, Label* fail) {
509 // ----------- S t a t e -------------
510 // -- eax : value
511 // -- ebx : target map
512 // -- ecx : key
513 // -- edx : receiver
514 // -- esp[0] : return address
515 // -----------------------------------
516 Label loop, entry, convert_hole, gc_required, only_change_map, success;
517
518 // Check for empty arrays, which only require a map transition and no changes
519 // to the backing store.
520 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
521 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
522 __ j(equal, &only_change_map);
523
524 __ push(eax);
525 __ push(edx);
526 __ push(ebx);
527
528 __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
529
530 // Allocate new FixedArray.
531 // ebx: length of source FixedDoubleArray (smi-tagged)
532 __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
533 __ AllocateInNewSpace(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
534
535 // eax: destination FixedArray
536 // ebx: number of elements
537 __ mov(FieldOperand(eax, HeapObject::kMapOffset),
538 Immediate(masm->isolate()->factory()->fixed_array_map()));
539 __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
540 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
541
542 __ jmp(&entry);
543
544 // ebx: target map
545 // edx: receiver
546 // Set transitioned map.
547 __ bind(&only_change_map);
548 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
549 __ RecordWriteField(edx,
550 HeapObject::kMapOffset,
551 ebx,
552 edi,
553 kDontSaveFPRegs,
554 OMIT_REMEMBERED_SET,
555 OMIT_SMI_CHECK);
556 __ jmp(&success);
557
558 // Call into runtime if GC is required.
559 __ bind(&gc_required);
560 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
561 __ pop(ebx);
562 __ pop(edx);
563 __ pop(eax);
564 __ jmp(fail);
565
566 // Box doubles into heap numbers.
567 // edi: source FixedDoubleArray
568 // eax: destination FixedArray
569 __ bind(&loop);
570 // ebx: index of current element (smi-tagged)
571 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
572 __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
573 __ j(equal, &convert_hole);
574
575 // Non-hole double, copy value into a heap number.
576 __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
577 // edx: new heap number
578 if (CpuFeatures::IsSupported(SSE2)) {
579 CpuFeatures::Scope fscope(SSE2);
580 __ movdbl(xmm0,
581 FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
582 __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
583 } else {
584 __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
585 __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
586 __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
587 __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
588 }
589 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
590 __ mov(esi, ebx);
591 __ RecordWriteArray(eax,
592 edx,
593 esi,
594 kDontSaveFPRegs,
595 EMIT_REMEMBERED_SET,
596 OMIT_SMI_CHECK);
597 __ jmp(&entry, Label::kNear);
598
599 // Replace the-hole NaN with the-hole pointer.
600 __ bind(&convert_hole);
601 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
602 masm->isolate()->factory()->the_hole_value());
603
604 __ bind(&entry);
605 __ sub(ebx, Immediate(Smi::FromInt(1)));
606 __ j(not_sign, &loop);
607
608 __ pop(ebx);
609 __ pop(edx);
610 // ebx: target map
611 // edx: receiver
612 // Set transitioned map.
613 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
614 __ RecordWriteField(edx,
615 HeapObject::kMapOffset,
616 ebx,
617 edi,
618 kDontSaveFPRegs,
619 OMIT_REMEMBERED_SET,
620 OMIT_SMI_CHECK);
621 // Replace receiver's backing store with newly created and filled FixedArray.
622 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
623 __ RecordWriteField(edx,
624 JSObject::kElementsOffset,
625 eax,
626 edi,
627 kDontSaveFPRegs,
628 EMIT_REMEMBERED_SET,
629 OMIT_SMI_CHECK);
630
631 // Restore registers.
632 __ pop(eax);
633 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
634
635 __ bind(&success);
636}
637
638
639void StringCharLoadGenerator::Generate(MacroAssembler* masm,
640 Factory* factory,
641 Register string,
642 Register index,
643 Register result,
644 Label* call_runtime) {
645 // Fetch the instance type of the receiver into result register.
646 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
647 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
648
649 // We need special handling for indirect strings.
650 Label check_sequential;
651 __ test(result, Immediate(kIsIndirectStringMask));
652 __ j(zero, &check_sequential, Label::kNear);
653
654 // Dispatch on the indirect string shape: slice or cons.
655 Label cons_string;
656 __ test(result, Immediate(kSlicedNotConsMask));
657 __ j(zero, &cons_string, Label::kNear);
658
659 // Handle slices.
660 Label indirect_string_loaded;
661 __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
662 __ SmiUntag(result);
663 __ add(index, result);
664 __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
665 __ jmp(&indirect_string_loaded, Label::kNear);
666
667 // Handle cons strings.
668 // Check whether the right hand side is the empty string (i.e. if
669 // this is really a flat string in a cons string). If that is not
670 // the case we would rather go to the runtime system now to flatten
671 // the string.
672 __ bind(&cons_string);
673 __ cmp(FieldOperand(string, ConsString::kSecondOffset),
674 Immediate(factory->empty_string()));
675 __ j(not_equal, call_runtime);
676 __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
677
678 __ bind(&indirect_string_loaded);
679 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
680 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
681
682 // Distinguish sequential and external strings. Only these two string
683 // representations can reach here (slices and flat cons strings have been
684 // reduced to the underlying sequential or external string).
685 Label seq_string;
686 __ bind(&check_sequential);
687 STATIC_ASSERT(kSeqStringTag == 0);
688 __ test(result, Immediate(kStringRepresentationMask));
689 __ j(zero, &seq_string, Label::kNear);
690
691 // Handle external strings.
692 Label ascii_external, done;
693 if (FLAG_debug_code) {
694 // Assert that we do not have a cons or slice (indirect strings) here.
695 // Sequential strings have already been ruled out.
696 __ test(result, Immediate(kIsIndirectStringMask));
697 __ Assert(zero, "external string expected, but not found");
698 }
699 // Rule out short external strings.
700 STATIC_CHECK(kShortExternalStringTag != 0);
701 __ test_b(result, kShortExternalStringMask);
702 __ j(not_zero, call_runtime);
703 // Check encoding.
704 STATIC_ASSERT(kTwoByteStringTag == 0);
705 __ test_b(result, kStringEncodingMask);
706 __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
707 __ j(not_equal, &ascii_external, Label::kNear);
708 // Two-byte string.
709 __ movzx_w(result, Operand(result, index, times_2, 0));
710 __ jmp(&done, Label::kNear);
711 __ bind(&ascii_external);
712 // Ascii string.
713 __ movzx_b(result, Operand(result, index, times_1, 0));
714 __ jmp(&done, Label::kNear);
715
716 // Dispatch on the encoding: ASCII or two-byte.
717 Label ascii;
718 __ bind(&seq_string);
719 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
720 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
721 __ test(result, Immediate(kStringEncodingMask));
722 __ j(not_zero, &ascii, Label::kNear);
723
724 // Two-byte string.
725 // Load the two-byte character code into the result register.
726 __ movzx_w(result, FieldOperand(string,
727 index,
728 times_2,
729 SeqTwoByteString::kHeaderSize));
730 __ jmp(&done, Label::kNear);
731
732 // Ascii string.
733 // Load the byte into the result register.
734 __ bind(&ascii);
735 __ movzx_b(result, FieldOperand(string,
736 index,
737 times_1,
738 SeqAsciiString::kHeaderSize));
739 __ bind(&done);
740}
741
742#undef __
743
Steve Blocka7e24c12009-10-30 11:49:00 +0000744} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +0100745
746#endif // V8_TARGET_ARCH_IA32