• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/ia32/codegen-ia32.h"
6 
7 #if V8_TARGET_ARCH_IA32
8 
9 #include "src/codegen.h"
10 #include "src/heap/heap.h"
11 #include "src/macro-assembler.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 
17 // -------------------------------------------------------------------------
18 // Platform-specific RuntimeCallHelper functions.
19 
BeforeCall(MacroAssembler * masm) const20 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
21   masm->EnterFrame(StackFrame::INTERNAL);
22   DCHECK(!masm->has_frame());
23   masm->set_has_frame(true);
24 }
25 
26 
AfterCall(MacroAssembler * masm) const27 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
28   masm->LeaveFrame(StackFrame::INTERNAL);
29   DCHECK(masm->has_frame());
30   masm->set_has_frame(false);
31 }
32 
33 
34 #define __ masm.
35 
36 
CreateSqrtFunction(Isolate * isolate)37 UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
38   size_t actual_size;
39   // Allocate buffer in executable space.
40   byte* buffer =
41       static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
42   if (buffer == nullptr) return nullptr;
43   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
44                       CodeObjectRequired::kNo);
45   // esp[1 * kPointerSize]: raw double input
46   // esp[0 * kPointerSize]: return address
47   // Move double input into registers.
48   {
49     __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
50     __ sqrtsd(xmm0, xmm0);
51     __ movsd(Operand(esp, 1 * kPointerSize), xmm0);
52     // Load result into floating point register as return value.
53     __ fld_d(Operand(esp, 1 * kPointerSize));
54     __ Ret();
55   }
56 
57   CodeDesc desc;
58   masm.GetCode(&desc);
59   DCHECK(!RelocInfo::RequiresRelocation(desc));
60 
61   Assembler::FlushICache(isolate, buffer, actual_size);
62   base::OS::ProtectCode(buffer, actual_size);
63   return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
64 }
65 
66 
67 // Helper functions for CreateMemMoveFunction.
68 #undef __
69 #define __ ACCESS_MASM(masm)
70 
71 enum Direction { FORWARD, BACKWARD };
72 enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
73 
74 // Expects registers:
75 // esi - source, aligned if alignment == ALIGNED
76 // edi - destination, always aligned
77 // ecx - count (copy size in bytes)
78 // edx - loop count (number of 64 byte chunks)
MemMoveEmitMainLoop(MacroAssembler * masm,Label * move_last_15,Direction direction,Alignment alignment)79 void MemMoveEmitMainLoop(MacroAssembler* masm,
80                          Label* move_last_15,
81                          Direction direction,
82                          Alignment alignment) {
83   Register src = esi;
84   Register dst = edi;
85   Register count = ecx;
86   Register loop_count = edx;
87   Label loop, move_last_31, move_last_63;
88   __ cmp(loop_count, 0);
89   __ j(equal, &move_last_63);
90   __ bind(&loop);
91   // Main loop. Copy in 64 byte chunks.
92   if (direction == BACKWARD) __ sub(src, Immediate(0x40));
93   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
94   __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
95   __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
96   __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
97   if (direction == FORWARD) __ add(src, Immediate(0x40));
98   if (direction == BACKWARD) __ sub(dst, Immediate(0x40));
99   __ movdqa(Operand(dst, 0x00), xmm0);
100   __ movdqa(Operand(dst, 0x10), xmm1);
101   __ movdqa(Operand(dst, 0x20), xmm2);
102   __ movdqa(Operand(dst, 0x30), xmm3);
103   if (direction == FORWARD) __ add(dst, Immediate(0x40));
104   __ dec(loop_count);
105   __ j(not_zero, &loop);
106   // At most 63 bytes left to copy.
107   __ bind(&move_last_63);
108   __ test(count, Immediate(0x20));
109   __ j(zero, &move_last_31);
110   if (direction == BACKWARD) __ sub(src, Immediate(0x20));
111   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
112   __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
113   if (direction == FORWARD) __ add(src, Immediate(0x20));
114   if (direction == BACKWARD) __ sub(dst, Immediate(0x20));
115   __ movdqa(Operand(dst, 0x00), xmm0);
116   __ movdqa(Operand(dst, 0x10), xmm1);
117   if (direction == FORWARD) __ add(dst, Immediate(0x20));
118   // At most 31 bytes left to copy.
119   __ bind(&move_last_31);
120   __ test(count, Immediate(0x10));
121   __ j(zero, move_last_15);
122   if (direction == BACKWARD) __ sub(src, Immediate(0x10));
123   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
124   if (direction == FORWARD) __ add(src, Immediate(0x10));
125   if (direction == BACKWARD) __ sub(dst, Immediate(0x10));
126   __ movdqa(Operand(dst, 0), xmm0);
127   if (direction == FORWARD) __ add(dst, Immediate(0x10));
128 }
129 
130 
MemMoveEmitPopAndReturn(MacroAssembler * masm)131 void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
132   __ pop(esi);
133   __ pop(edi);
134   __ ret(0);
135 }
136 
137 
138 #undef __
139 #define __ masm.
140 
141 
142 class LabelConverter {
143  public:
LabelConverter(byte * buffer)144   explicit LabelConverter(byte* buffer) : buffer_(buffer) {}
address(Label * l) const145   int32_t address(Label* l) const {
146     return reinterpret_cast<int32_t>(buffer_) + l->pos();
147   }
148  private:
149   byte* buffer_;
150 };
151 
152 
CreateMemMoveFunction(Isolate * isolate)153 MemMoveFunction CreateMemMoveFunction(Isolate* isolate) {
154   size_t actual_size;
155   // Allocate buffer in executable space.
156   byte* buffer =
157       static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
158   if (buffer == nullptr) return nullptr;
159   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
160                       CodeObjectRequired::kNo);
161   LabelConverter conv(buffer);
162 
163   // Generated code is put into a fixed, unmovable buffer, and not into
164   // the V8 heap. We can't, and don't, refer to any relocatable addresses
165   // (e.g. the JavaScript nan-object).
166 
167   // 32-bit C declaration function calls pass arguments on stack.
168 
169   // Stack layout:
170   // esp[12]: Third argument, size.
171   // esp[8]: Second argument, source pointer.
172   // esp[4]: First argument, destination pointer.
173   // esp[0]: return address
174 
175   const int kDestinationOffset = 1 * kPointerSize;
176   const int kSourceOffset = 2 * kPointerSize;
177   const int kSizeOffset = 3 * kPointerSize;
178 
179   // When copying up to this many bytes, use special "small" handlers.
180   const size_t kSmallCopySize = 8;
181   // When copying up to this many bytes, use special "medium" handlers.
182   const size_t kMediumCopySize = 63;
183   // When non-overlapping region of src and dst is less than this,
184   // use a more careful implementation (slightly slower).
185   const size_t kMinMoveDistance = 16;
186   // Note that these values are dictated by the implementation below,
187   // do not just change them and hope things will work!
188 
189   int stack_offset = 0;  // Update if we change the stack height.
190 
191   Label backward, backward_much_overlap;
192   Label forward_much_overlap, small_size, medium_size, pop_and_return;
193   __ push(edi);
194   __ push(esi);
195   stack_offset += 2 * kPointerSize;
196   Register dst = edi;
197   Register src = esi;
198   Register count = ecx;
199   Register loop_count = edx;
200   __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
201   __ mov(src, Operand(esp, stack_offset + kSourceOffset));
202   __ mov(count, Operand(esp, stack_offset + kSizeOffset));
203 
204   __ cmp(dst, src);
205   __ j(equal, &pop_and_return);
206 
207   __ prefetch(Operand(src, 0), 1);
208   __ cmp(count, kSmallCopySize);
209   __ j(below_equal, &small_size);
210   __ cmp(count, kMediumCopySize);
211   __ j(below_equal, &medium_size);
212   __ cmp(dst, src);
213   __ j(above, &backward);
214 
215   {
216     // |dst| is a lower address than |src|. Copy front-to-back.
217     Label unaligned_source, move_last_15, skip_last_move;
218     __ mov(eax, src);
219     __ sub(eax, dst);
220     __ cmp(eax, kMinMoveDistance);
221     __ j(below, &forward_much_overlap);
222     // Copy first 16 bytes.
223     __ movdqu(xmm0, Operand(src, 0));
224     __ movdqu(Operand(dst, 0), xmm0);
225     // Determine distance to alignment: 16 - (dst & 0xF).
226     __ mov(edx, dst);
227     __ and_(edx, 0xF);
228     __ neg(edx);
229     __ add(edx, Immediate(16));
230     __ add(dst, edx);
231     __ add(src, edx);
232     __ sub(count, edx);
233     // dst is now aligned. Main copy loop.
234     __ mov(loop_count, count);
235     __ shr(loop_count, 6);
236     // Check if src is also aligned.
237     __ test(src, Immediate(0xF));
238     __ j(not_zero, &unaligned_source);
239     // Copy loop for aligned source and destination.
240     MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
241     // At most 15 bytes to copy. Copy 16 bytes at end of string.
242     __ bind(&move_last_15);
243     __ and_(count, 0xF);
244     __ j(zero, &skip_last_move, Label::kNear);
245     __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
246     __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
247     __ bind(&skip_last_move);
248     MemMoveEmitPopAndReturn(&masm);
249 
250     // Copy loop for unaligned source and aligned destination.
251     __ bind(&unaligned_source);
252     MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
253     __ jmp(&move_last_15);
254 
255     // Less than kMinMoveDistance offset between dst and src.
256     Label loop_until_aligned, last_15_much_overlap;
257     __ bind(&loop_until_aligned);
258     __ mov_b(eax, Operand(src, 0));
259     __ inc(src);
260     __ mov_b(Operand(dst, 0), eax);
261     __ inc(dst);
262     __ dec(count);
263     __ bind(&forward_much_overlap);  // Entry point into this block.
264     __ test(dst, Immediate(0xF));
265     __ j(not_zero, &loop_until_aligned);
266     // dst is now aligned, src can't be. Main copy loop.
267     __ mov(loop_count, count);
268     __ shr(loop_count, 6);
269     MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
270                         FORWARD, MOVE_UNALIGNED);
271     __ bind(&last_15_much_overlap);
272     __ and_(count, 0xF);
273     __ j(zero, &pop_and_return);
274     __ cmp(count, kSmallCopySize);
275     __ j(below_equal, &small_size);
276     __ jmp(&medium_size);
277   }
278 
279   {
280     // |dst| is a higher address than |src|. Copy backwards.
281     Label unaligned_source, move_first_15, skip_last_move;
282     __ bind(&backward);
283     // |dst| and |src| always point to the end of what's left to copy.
284     __ add(dst, count);
285     __ add(src, count);
286     __ mov(eax, dst);
287     __ sub(eax, src);
288     __ cmp(eax, kMinMoveDistance);
289     __ j(below, &backward_much_overlap);
290     // Copy last 16 bytes.
291     __ movdqu(xmm0, Operand(src, -0x10));
292     __ movdqu(Operand(dst, -0x10), xmm0);
293     // Find distance to alignment: dst & 0xF
294     __ mov(edx, dst);
295     __ and_(edx, 0xF);
296     __ sub(dst, edx);
297     __ sub(src, edx);
298     __ sub(count, edx);
299     // dst is now aligned. Main copy loop.
300     __ mov(loop_count, count);
301     __ shr(loop_count, 6);
302     // Check if src is also aligned.
303     __ test(src, Immediate(0xF));
304     __ j(not_zero, &unaligned_source);
305     // Copy loop for aligned source and destination.
306     MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
307     // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
308     __ bind(&move_first_15);
309     __ and_(count, 0xF);
310     __ j(zero, &skip_last_move, Label::kNear);
311     __ sub(src, count);
312     __ sub(dst, count);
313     __ movdqu(xmm0, Operand(src, 0));
314     __ movdqu(Operand(dst, 0), xmm0);
315     __ bind(&skip_last_move);
316     MemMoveEmitPopAndReturn(&masm);
317 
318     // Copy loop for unaligned source and aligned destination.
319     __ bind(&unaligned_source);
320     MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
321     __ jmp(&move_first_15);
322 
323     // Less than kMinMoveDistance offset between dst and src.
324     Label loop_until_aligned, first_15_much_overlap;
325     __ bind(&loop_until_aligned);
326     __ dec(src);
327     __ dec(dst);
328     __ mov_b(eax, Operand(src, 0));
329     __ mov_b(Operand(dst, 0), eax);
330     __ dec(count);
331     __ bind(&backward_much_overlap);  // Entry point into this block.
332     __ test(dst, Immediate(0xF));
333     __ j(not_zero, &loop_until_aligned);
334     // dst is now aligned, src can't be. Main copy loop.
335     __ mov(loop_count, count);
336     __ shr(loop_count, 6);
337     MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
338                         BACKWARD, MOVE_UNALIGNED);
339     __ bind(&first_15_much_overlap);
340     __ and_(count, 0xF);
341     __ j(zero, &pop_and_return);
342     // Small/medium handlers expect dst/src to point to the beginning.
343     __ sub(dst, count);
344     __ sub(src, count);
345     __ cmp(count, kSmallCopySize);
346     __ j(below_equal, &small_size);
347     __ jmp(&medium_size);
348   }
349   {
350     // Special handlers for 9 <= copy_size < 64. No assumptions about
351     // alignment or move distance, so all reads must be unaligned and
352     // must happen before any writes.
353     Label medium_handlers, f9_16, f17_32, f33_48, f49_63;
354 
355     __ bind(&f9_16);
356     __ movsd(xmm0, Operand(src, 0));
357     __ movsd(xmm1, Operand(src, count, times_1, -8));
358     __ movsd(Operand(dst, 0), xmm0);
359     __ movsd(Operand(dst, count, times_1, -8), xmm1);
360     MemMoveEmitPopAndReturn(&masm);
361 
362     __ bind(&f17_32);
363     __ movdqu(xmm0, Operand(src, 0));
364     __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
365     __ movdqu(Operand(dst, 0x00), xmm0);
366     __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
367     MemMoveEmitPopAndReturn(&masm);
368 
369     __ bind(&f33_48);
370     __ movdqu(xmm0, Operand(src, 0x00));
371     __ movdqu(xmm1, Operand(src, 0x10));
372     __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
373     __ movdqu(Operand(dst, 0x00), xmm0);
374     __ movdqu(Operand(dst, 0x10), xmm1);
375     __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
376     MemMoveEmitPopAndReturn(&masm);
377 
378     __ bind(&f49_63);
379     __ movdqu(xmm0, Operand(src, 0x00));
380     __ movdqu(xmm1, Operand(src, 0x10));
381     __ movdqu(xmm2, Operand(src, 0x20));
382     __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
383     __ movdqu(Operand(dst, 0x00), xmm0);
384     __ movdqu(Operand(dst, 0x10), xmm1);
385     __ movdqu(Operand(dst, 0x20), xmm2);
386     __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
387     MemMoveEmitPopAndReturn(&masm);
388 
389     __ bind(&medium_handlers);
390     __ dd(conv.address(&f9_16));
391     __ dd(conv.address(&f17_32));
392     __ dd(conv.address(&f33_48));
393     __ dd(conv.address(&f49_63));
394 
395     __ bind(&medium_size);  // Entry point into this block.
396     __ mov(eax, count);
397     __ dec(eax);
398     __ shr(eax, 4);
399     if (FLAG_debug_code) {
400       Label ok;
401       __ cmp(eax, 3);
402       __ j(below_equal, &ok);
403       __ int3();
404       __ bind(&ok);
405     }
406     __ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers)));
407     __ jmp(eax);
408   }
409   {
410     // Specialized copiers for copy_size <= 8 bytes.
411     Label small_handlers, f0, f1, f2, f3, f4, f5_8;
412     __ bind(&f0);
413     MemMoveEmitPopAndReturn(&masm);
414 
415     __ bind(&f1);
416     __ mov_b(eax, Operand(src, 0));
417     __ mov_b(Operand(dst, 0), eax);
418     MemMoveEmitPopAndReturn(&masm);
419 
420     __ bind(&f2);
421     __ mov_w(eax, Operand(src, 0));
422     __ mov_w(Operand(dst, 0), eax);
423     MemMoveEmitPopAndReturn(&masm);
424 
425     __ bind(&f3);
426     __ mov_w(eax, Operand(src, 0));
427     __ mov_b(edx, Operand(src, 2));
428     __ mov_w(Operand(dst, 0), eax);
429     __ mov_b(Operand(dst, 2), edx);
430     MemMoveEmitPopAndReturn(&masm);
431 
432     __ bind(&f4);
433     __ mov(eax, Operand(src, 0));
434     __ mov(Operand(dst, 0), eax);
435     MemMoveEmitPopAndReturn(&masm);
436 
437     __ bind(&f5_8);
438     __ mov(eax, Operand(src, 0));
439     __ mov(edx, Operand(src, count, times_1, -4));
440     __ mov(Operand(dst, 0), eax);
441     __ mov(Operand(dst, count, times_1, -4), edx);
442     MemMoveEmitPopAndReturn(&masm);
443 
444     __ bind(&small_handlers);
445     __ dd(conv.address(&f0));
446     __ dd(conv.address(&f1));
447     __ dd(conv.address(&f2));
448     __ dd(conv.address(&f3));
449     __ dd(conv.address(&f4));
450     __ dd(conv.address(&f5_8));
451     __ dd(conv.address(&f5_8));
452     __ dd(conv.address(&f5_8));
453     __ dd(conv.address(&f5_8));
454 
455     __ bind(&small_size);  // Entry point into this block.
456     if (FLAG_debug_code) {
457       Label ok;
458       __ cmp(count, 8);
459       __ j(below_equal, &ok);
460       __ int3();
461       __ bind(&ok);
462     }
463     __ mov(eax, Operand(count, times_4, conv.address(&small_handlers)));
464     __ jmp(eax);
465   }
466 
467   __ bind(&pop_and_return);
468   MemMoveEmitPopAndReturn(&masm);
469 
470   CodeDesc desc;
471   masm.GetCode(&desc);
472   DCHECK(!RelocInfo::RequiresRelocation(desc));
473   Assembler::FlushICache(isolate, buffer, actual_size);
474   base::OS::ProtectCode(buffer, actual_size);
475   // TODO(jkummerow): It would be nice to register this code creation event
476   // with the PROFILE / GDBJIT system.
477   return FUNCTION_CAST<MemMoveFunction>(buffer);
478 }
479 
480 
481 #undef __
482 
483 // -------------------------------------------------------------------------
484 // Code generators
485 
486 #define __ ACCESS_MASM(masm)
487 
Generate(MacroAssembler * masm,Factory * factory,Register string,Register index,Register result,Label * call_runtime)488 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
489                                        Factory* factory,
490                                        Register string,
491                                        Register index,
492                                        Register result,
493                                        Label* call_runtime) {
494   Label indirect_string_loaded;
495   __ bind(&indirect_string_loaded);
496 
497   // Fetch the instance type of the receiver into result register.
498   __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
499   __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
500 
501   // We need special handling for indirect strings.
502   Label check_sequential;
503   __ test(result, Immediate(kIsIndirectStringMask));
504   __ j(zero, &check_sequential, Label::kNear);
505 
506   // Dispatch on the indirect string shape: slice or cons.
507   Label cons_string, thin_string;
508   __ and_(result, Immediate(kStringRepresentationMask));
509   __ cmp(result, Immediate(kConsStringTag));
510   __ j(equal, &cons_string, Label::kNear);
511   __ cmp(result, Immediate(kThinStringTag));
512   __ j(equal, &thin_string, Label::kNear);
513 
514   // Handle slices.
515   __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
516   __ SmiUntag(result);
517   __ add(index, result);
518   __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
519   __ jmp(&indirect_string_loaded);
520 
521   // Handle thin strings.
522   __ bind(&thin_string);
523   __ mov(string, FieldOperand(string, ThinString::kActualOffset));
524   __ jmp(&indirect_string_loaded);
525 
526   // Handle cons strings.
527   // Check whether the right hand side is the empty string (i.e. if
528   // this is really a flat string in a cons string). If that is not
529   // the case we would rather go to the runtime system now to flatten
530   // the string.
531   __ bind(&cons_string);
532   __ cmp(FieldOperand(string, ConsString::kSecondOffset),
533          Immediate(factory->empty_string()));
534   __ j(not_equal, call_runtime);
535   __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
536   __ jmp(&indirect_string_loaded);
537 
538   // Distinguish sequential and external strings. Only these two string
539   // representations can reach here (slices and flat cons strings have been
540   // reduced to the underlying sequential or external string).
541   Label seq_string;
542   __ bind(&check_sequential);
543   STATIC_ASSERT(kSeqStringTag == 0);
544   __ test(result, Immediate(kStringRepresentationMask));
545   __ j(zero, &seq_string, Label::kNear);
546 
547   // Handle external strings.
548   Label one_byte_external, done;
549   if (FLAG_debug_code) {
550     // Assert that we do not have a cons or slice (indirect strings) here.
551     // Sequential strings have already been ruled out.
552     __ test(result, Immediate(kIsIndirectStringMask));
553     __ Assert(zero, kExternalStringExpectedButNotFound);
554   }
555   // Rule out short external strings.
556   STATIC_ASSERT(kShortExternalStringTag != 0);
557   __ test_b(result, Immediate(kShortExternalStringMask));
558   __ j(not_zero, call_runtime);
559   // Check encoding.
560   STATIC_ASSERT(kTwoByteStringTag == 0);
561   __ test_b(result, Immediate(kStringEncodingMask));
562   __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
563   __ j(not_equal, &one_byte_external, Label::kNear);
564   // Two-byte string.
565   __ movzx_w(result, Operand(result, index, times_2, 0));
566   __ jmp(&done, Label::kNear);
567   __ bind(&one_byte_external);
568   // One-byte string.
569   __ movzx_b(result, Operand(result, index, times_1, 0));
570   __ jmp(&done, Label::kNear);
571 
572   // Dispatch on the encoding: one-byte or two-byte.
573   Label one_byte;
574   __ bind(&seq_string);
575   STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
576   STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
577   __ test(result, Immediate(kStringEncodingMask));
578   __ j(not_zero, &one_byte, Label::kNear);
579 
580   // Two-byte string.
581   // Load the two-byte character code into the result register.
582   __ movzx_w(result, FieldOperand(string,
583                                   index,
584                                   times_2,
585                                   SeqTwoByteString::kHeaderSize));
586   __ jmp(&done, Label::kNear);
587 
588   // One-byte string.
589   // Load the byte into the result register.
590   __ bind(&one_byte);
591   __ movzx_b(result, FieldOperand(string,
592                                   index,
593                                   times_1,
594                                   SeqOneByteString::kHeaderSize));
595   __ bind(&done);
596 }
597 
598 #undef __
599 
600 
CodeAgingHelper(Isolate * isolate)601 CodeAgingHelper::CodeAgingHelper(Isolate* isolate) {
602   USE(isolate);
603   DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
604   CodePatcher patcher(isolate, young_sequence_.start(),
605                       young_sequence_.length());
606   patcher.masm()->push(ebp);
607   patcher.masm()->mov(ebp, esp);
608   patcher.masm()->push(esi);
609   patcher.masm()->push(edi);
610 }
611 
612 
613 #ifdef DEBUG
IsOld(byte * candidate) const614 bool CodeAgingHelper::IsOld(byte* candidate) const {
615   return *candidate == kCallOpcode;
616 }
617 #endif
618 
619 
IsYoungSequence(Isolate * isolate,byte * sequence)620 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
621   bool result = isolate->code_aging_helper()->IsYoung(sequence);
622   DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
623   return result;
624 }
625 
GetCodeAge(Isolate * isolate,byte * sequence)626 Code::Age Code::GetCodeAge(Isolate* isolate, byte* sequence) {
627   if (IsYoungSequence(isolate, sequence)) return kNoAgeCodeAge;
628 
629   sequence++;  // Skip the kCallOpcode byte
630   Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
631                            Assembler::kCallTargetAddressOffset;
632   Code* stub = GetCodeFromTargetAddress(target_address);
633   return GetAgeOfCodeAgeStub(stub);
634 }
635 
PatchPlatformCodeAge(Isolate * isolate,byte * sequence,Code::Age age)636 void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence,
637                                 Code::Age age) {
638   uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
639   if (age == kNoAgeCodeAge) {
640     isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
641     Assembler::FlushICache(isolate, sequence, young_length);
642   } else {
643     Code* stub = GetCodeAgeStub(isolate, age);
644     CodePatcher patcher(isolate, sequence, young_length);
645     patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
646   }
647 }
648 
649 
650 }  // namespace internal
651 }  // namespace v8
652 
653 #endif  // V8_TARGET_ARCH_IA32
654