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/x87/codegen-x87.h"
6 
7 #if V8_TARGET_ARCH_X87
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 
44   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
45                       CodeObjectRequired::kNo);
46   // Load double input into registers.
47   __ fld_d(MemOperand(esp, 4));
48   __ X87SetFPUCW(0x027F);
49   __ fsqrt();
50   __ X87SetFPUCW(0x037F);
51   __ Ret();
52 
53   CodeDesc desc;
54   masm.GetCode(&desc);
55   DCHECK(!RelocInfo::RequiresRelocation(desc));
56 
57   Assembler::FlushICache(isolate, buffer, actual_size);
58   base::OS::ProtectCode(buffer, actual_size);
59   return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
60 }
61 
62 
63 // Helper functions for CreateMemMoveFunction.
64 #undef __
65 #define __ ACCESS_MASM(masm)
66 
67 enum Direction { FORWARD, BACKWARD };
68 enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
69 
70 
MemMoveEmitPopAndReturn(MacroAssembler * masm)71 void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
72   __ pop(esi);
73   __ pop(edi);
74   __ ret(0);
75 }
76 
77 
78 #undef __
79 #define __ masm.
80 
81 
82 class LabelConverter {
83  public:
LabelConverter(byte * buffer)84   explicit LabelConverter(byte* buffer) : buffer_(buffer) {}
address(Label * l) const85   int32_t address(Label* l) const {
86     return reinterpret_cast<int32_t>(buffer_) + l->pos();
87   }
88  private:
89   byte* buffer_;
90 };
91 
92 
CreateMemMoveFunction(Isolate * isolate)93 MemMoveFunction CreateMemMoveFunction(Isolate* isolate) {
94   size_t actual_size;
95   // Allocate buffer in executable space.
96   byte* buffer =
97       static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
98   if (buffer == nullptr) return nullptr;
99   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
100                       CodeObjectRequired::kNo);
101   LabelConverter conv(buffer);
102 
103   // Generated code is put into a fixed, unmovable buffer, and not into
104   // the V8 heap. We can't, and don't, refer to any relocatable addresses
105   // (e.g. the JavaScript nan-object).
106 
107   // 32-bit C declaration function calls pass arguments on stack.
108 
109   // Stack layout:
110   // esp[12]: Third argument, size.
111   // esp[8]: Second argument, source pointer.
112   // esp[4]: First argument, destination pointer.
113   // esp[0]: return address
114 
115   const int kDestinationOffset = 1 * kPointerSize;
116   const int kSourceOffset = 2 * kPointerSize;
117   const int kSizeOffset = 3 * kPointerSize;
118 
119   int stack_offset = 0;  // Update if we change the stack height.
120 
121   Label backward, backward_much_overlap;
122   Label forward_much_overlap, small_size, medium_size, pop_and_return;
123   __ push(edi);
124   __ push(esi);
125   stack_offset += 2 * kPointerSize;
126   Register dst = edi;
127   Register src = esi;
128   Register count = ecx;
129   __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
130   __ mov(src, Operand(esp, stack_offset + kSourceOffset));
131   __ mov(count, Operand(esp, stack_offset + kSizeOffset));
132 
133   __ cmp(dst, src);
134   __ j(equal, &pop_and_return);
135 
136   // No SSE2.
137   Label forward;
138   __ cmp(count, 0);
139   __ j(equal, &pop_and_return);
140   __ cmp(dst, src);
141   __ j(above, &backward);
142   __ jmp(&forward);
143   {
144     // Simple forward copier.
145     Label forward_loop_1byte, forward_loop_4byte;
146     __ bind(&forward_loop_4byte);
147     __ mov(eax, Operand(src, 0));
148     __ sub(count, Immediate(4));
149     __ add(src, Immediate(4));
150     __ mov(Operand(dst, 0), eax);
151     __ add(dst, Immediate(4));
152     __ bind(&forward);  // Entry point.
153     __ cmp(count, 3);
154     __ j(above, &forward_loop_4byte);
155     __ bind(&forward_loop_1byte);
156     __ cmp(count, 0);
157     __ j(below_equal, &pop_and_return);
158     __ mov_b(eax, Operand(src, 0));
159     __ dec(count);
160     __ inc(src);
161     __ mov_b(Operand(dst, 0), eax);
162     __ inc(dst);
163     __ jmp(&forward_loop_1byte);
164   }
165   {
166     // Simple backward copier.
167     Label backward_loop_1byte, backward_loop_4byte, entry_shortcut;
168     __ bind(&backward);
169     __ add(src, count);
170     __ add(dst, count);
171     __ cmp(count, 3);
172     __ j(below_equal, &entry_shortcut);
173 
174     __ bind(&backward_loop_4byte);
175     __ sub(src, Immediate(4));
176     __ sub(count, Immediate(4));
177     __ mov(eax, Operand(src, 0));
178     __ sub(dst, Immediate(4));
179     __ mov(Operand(dst, 0), eax);
180     __ cmp(count, 3);
181     __ j(above, &backward_loop_4byte);
182     __ bind(&backward_loop_1byte);
183     __ cmp(count, 0);
184     __ j(below_equal, &pop_and_return);
185     __ bind(&entry_shortcut);
186     __ dec(src);
187     __ dec(count);
188     __ mov_b(eax, Operand(src, 0));
189     __ dec(dst);
190     __ mov_b(Operand(dst, 0), eax);
191     __ jmp(&backward_loop_1byte);
192   }
193 
194   __ bind(&pop_and_return);
195   MemMoveEmitPopAndReturn(&masm);
196 
197   CodeDesc desc;
198   masm.GetCode(&desc);
199   DCHECK(!RelocInfo::RequiresRelocation(desc));
200   Assembler::FlushICache(isolate, buffer, actual_size);
201   base::OS::ProtectCode(buffer, actual_size);
202   // TODO(jkummerow): It would be nice to register this code creation event
203   // with the PROFILE / GDBJIT system.
204   return FUNCTION_CAST<MemMoveFunction>(buffer);
205 }
206 
207 
208 #undef __
209 
210 // -------------------------------------------------------------------------
211 // Code generators
212 
213 #define __ ACCESS_MASM(masm)
214 
215 
GenerateMapChangeElementsTransition(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * allocation_memento_found)216 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
217     MacroAssembler* masm,
218     Register receiver,
219     Register key,
220     Register value,
221     Register target_map,
222     AllocationSiteMode mode,
223     Label* allocation_memento_found) {
224   Register scratch = edi;
225   DCHECK(!AreAliased(receiver, key, value, target_map, scratch));
226 
227   if (mode == TRACK_ALLOCATION_SITE) {
228     DCHECK(allocation_memento_found != NULL);
229     __ JumpIfJSArrayHasAllocationMemento(
230         receiver, scratch, allocation_memento_found);
231   }
232 
233   // Set transitioned map.
234   __ mov(FieldOperand(receiver, HeapObject::kMapOffset), target_map);
235   __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch,
236                       kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
237 }
238 
239 
GenerateSmiToDouble(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * fail)240 void ElementsTransitionGenerator::GenerateSmiToDouble(
241     MacroAssembler* masm,
242     Register receiver,
243     Register key,
244     Register value,
245     Register target_map,
246     AllocationSiteMode mode,
247     Label* fail) {
248   // Return address is on the stack.
249   DCHECK(receiver.is(edx));
250   DCHECK(key.is(ecx));
251   DCHECK(value.is(eax));
252   DCHECK(target_map.is(ebx));
253 
254   Label loop, entry, convert_hole, gc_required, only_change_map;
255 
256   if (mode == TRACK_ALLOCATION_SITE) {
257     __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail);
258   }
259 
260   // Check for empty arrays, which only require a map transition and no changes
261   // to the backing store.
262   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
263   __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
264   __ j(equal, &only_change_map);
265 
266   __ push(eax);
267   __ push(ebx);
268   __ push(esi);
269 
270   __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
271 
272   // Allocate new FixedDoubleArray.
273   // edx: receiver
274   // edi: length of source FixedArray (smi-tagged)
275   AllocationFlags flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT);
276   __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi,
277               REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags);
278 
279   // eax: destination FixedDoubleArray
280   // edi: number of elements
281   // edx: receiver
282   __ mov(FieldOperand(eax, HeapObject::kMapOffset),
283          Immediate(masm->isolate()->factory()->fixed_double_array_map()));
284   __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
285   __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
286   // Replace receiver's backing store with newly created FixedDoubleArray.
287   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
288   __ mov(ebx, eax);
289   __ RecordWriteField(edx, JSObject::kElementsOffset, ebx, edi, kDontSaveFPRegs,
290                       EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
291 
292   __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
293 
294   // Prepare for conversion loop.
295   ExternalReference canonical_the_hole_nan_reference =
296       ExternalReference::address_of_the_hole_nan();
297   __ jmp(&entry);
298 
299   // Call into runtime if GC is required.
300   __ bind(&gc_required);
301 
302   // Restore registers before jumping into runtime.
303   __ pop(esi);
304   __ pop(ebx);
305   __ pop(eax);
306   __ jmp(fail);
307 
308   // Convert and copy elements
309   // esi: source FixedArray
310   __ bind(&loop);
311   __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
312   // ebx: current element from source
313   // edi: index of current element
314   __ JumpIfNotSmi(ebx, &convert_hole);
315 
316   // Normal smi, convert it to double and store.
317   __ SmiUntag(ebx);
318   __ push(ebx);
319   __ fild_s(Operand(esp, 0));
320   __ pop(ebx);
321   __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
322   __ jmp(&entry);
323 
324   // Found hole, store hole_nan_as_double instead.
325   __ bind(&convert_hole);
326 
327   if (FLAG_debug_code) {
328     __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
329     __ Assert(equal, kObjectFoundInSmiOnlyArray);
330   }
331 
332   __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
333   __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
334 
335   __ bind(&entry);
336   __ sub(edi, Immediate(Smi::FromInt(1)));
337   __ j(not_sign, &loop);
338 
339   // Restore registers.
340   __ pop(esi);
341   __ pop(ebx);
342   __ pop(eax);
343 
344   __ bind(&only_change_map);
345   // eax: value
346   // ebx: target map
347   // Set transitioned map.
348   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
349   __ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
350                       OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
351 }
352 
353 
GenerateDoubleToObject(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * fail)354 void ElementsTransitionGenerator::GenerateDoubleToObject(
355     MacroAssembler* masm,
356     Register receiver,
357     Register key,
358     Register value,
359     Register target_map,
360     AllocationSiteMode mode,
361     Label* fail) {
362   // Return address is on the stack.
363   DCHECK(receiver.is(edx));
364   DCHECK(key.is(ecx));
365   DCHECK(value.is(eax));
366   DCHECK(target_map.is(ebx));
367 
368   Label loop, entry, convert_hole, gc_required, only_change_map, success;
369 
370   if (mode == TRACK_ALLOCATION_SITE) {
371     __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail);
372   }
373 
374   // Check for empty arrays, which only require a map transition and no changes
375   // to the backing store.
376   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
377   __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
378   __ j(equal, &only_change_map);
379 
380   __ push(esi);
381   __ push(eax);
382   __ push(edx);
383   __ push(ebx);
384 
385   __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
386 
387   // Allocate new FixedArray.
388   // ebx: length of source FixedDoubleArray (smi-tagged)
389   __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
390   __ Allocate(edi, eax, esi, no_reg, &gc_required, NO_ALLOCATION_FLAGS);
391 
392   // eax: destination FixedArray
393   // ebx: number of elements
394   __ mov(FieldOperand(eax, HeapObject::kMapOffset),
395          Immediate(masm->isolate()->factory()->fixed_array_map()));
396   __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
397   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
398 
399   // Allocating heap numbers in the loop below can fail and cause a jump to
400   // gc_required. We can't leave a partly initialized FixedArray behind,
401   // so pessimistically fill it with holes now.
402   Label initialization_loop, initialization_loop_entry;
403   __ jmp(&initialization_loop_entry, Label::kNear);
404   __ bind(&initialization_loop);
405   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
406          masm->isolate()->factory()->the_hole_value());
407   __ bind(&initialization_loop_entry);
408   __ sub(ebx, Immediate(Smi::FromInt(1)));
409   __ j(not_sign, &initialization_loop);
410 
411   __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
412   __ jmp(&entry);
413 
414   // ebx: target map
415   // edx: receiver
416   // Set transitioned map.
417   __ bind(&only_change_map);
418   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
419   __ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
420                       OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
421   __ jmp(&success);
422 
423   // Call into runtime if GC is required.
424   __ bind(&gc_required);
425   __ pop(ebx);
426   __ pop(edx);
427   __ pop(eax);
428   __ pop(esi);
429   __ jmp(fail);
430 
431   // Box doubles into heap numbers.
432   // edi: source FixedDoubleArray
433   // eax: destination FixedArray
434   __ bind(&loop);
435   // ebx: index of current element (smi-tagged)
436   uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
437   __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
438   __ j(equal, &convert_hole);
439 
440   // Non-hole double, copy value into a heap number.
441   __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
442   // edx: new heap number
443   __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
444   __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
445   __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
446   __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
447   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
448   __ mov(esi, ebx);
449   __ RecordWriteArray(eax, edx, esi, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
450                       OMIT_SMI_CHECK);
451   __ jmp(&entry, Label::kNear);
452 
453   // Replace the-hole NaN with the-hole pointer.
454   __ bind(&convert_hole);
455   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
456          masm->isolate()->factory()->the_hole_value());
457 
458   __ bind(&entry);
459   __ sub(ebx, Immediate(Smi::FromInt(1)));
460   __ j(not_sign, &loop);
461 
462   __ pop(ebx);
463   __ pop(edx);
464   // ebx: target map
465   // edx: receiver
466   // Set transitioned map.
467   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
468   __ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
469                       OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
470   // Replace receiver's backing store with newly created and filled FixedArray.
471   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
472   __ RecordWriteField(edx, JSObject::kElementsOffset, eax, edi, kDontSaveFPRegs,
473                       EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
474 
475   // Restore registers.
476   __ pop(eax);
477   __ pop(esi);
478 
479   __ bind(&success);
480 }
481 
482 
Generate(MacroAssembler * masm,Factory * factory,Register string,Register index,Register result,Label * call_runtime)483 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
484                                        Factory* factory,
485                                        Register string,
486                                        Register index,
487                                        Register result,
488                                        Label* call_runtime) {
489   // Fetch the instance type of the receiver into result register.
490   __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
491   __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
492 
493   // We need special handling for indirect strings.
494   Label check_sequential;
495   __ test(result, Immediate(kIsIndirectStringMask));
496   __ j(zero, &check_sequential, Label::kNear);
497 
498   // Dispatch on the indirect string shape: slice or cons.
499   Label cons_string;
500   __ test(result, Immediate(kSlicedNotConsMask));
501   __ j(zero, &cons_string, Label::kNear);
502 
503   // Handle slices.
504   Label indirect_string_loaded;
505   __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
506   __ SmiUntag(result);
507   __ add(index, result);
508   __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
509   __ jmp(&indirect_string_loaded, Label::kNear);
510 
511   // Handle cons strings.
512   // Check whether the right hand side is the empty string (i.e. if
513   // this is really a flat string in a cons string). If that is not
514   // the case we would rather go to the runtime system now to flatten
515   // the string.
516   __ bind(&cons_string);
517   __ cmp(FieldOperand(string, ConsString::kSecondOffset),
518          Immediate(factory->empty_string()));
519   __ j(not_equal, call_runtime);
520   __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
521 
522   __ bind(&indirect_string_loaded);
523   __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
524   __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
525 
526   // Distinguish sequential and external strings. Only these two string
527   // representations can reach here (slices and flat cons strings have been
528   // reduced to the underlying sequential or external string).
529   Label seq_string;
530   __ bind(&check_sequential);
531   STATIC_ASSERT(kSeqStringTag == 0);
532   __ test(result, Immediate(kStringRepresentationMask));
533   __ j(zero, &seq_string, Label::kNear);
534 
535   // Handle external strings.
536   Label one_byte_external, done;
537   if (FLAG_debug_code) {
538     // Assert that we do not have a cons or slice (indirect strings) here.
539     // Sequential strings have already been ruled out.
540     __ test(result, Immediate(kIsIndirectStringMask));
541     __ Assert(zero, kExternalStringExpectedButNotFound);
542   }
543   // Rule out short external strings.
544   STATIC_ASSERT(kShortExternalStringTag != 0);
545   __ test_b(result, Immediate(kShortExternalStringMask));
546   __ j(not_zero, call_runtime);
547   // Check encoding.
548   STATIC_ASSERT(kTwoByteStringTag == 0);
549   __ test_b(result, Immediate(kStringEncodingMask));
550   __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
551   __ j(not_equal, &one_byte_external, Label::kNear);
552   // Two-byte string.
553   __ movzx_w(result, Operand(result, index, times_2, 0));
554   __ jmp(&done, Label::kNear);
555   __ bind(&one_byte_external);
556   // One-byte string.
557   __ movzx_b(result, Operand(result, index, times_1, 0));
558   __ jmp(&done, Label::kNear);
559 
560   // Dispatch on the encoding: one-byte or two-byte.
561   Label one_byte;
562   __ bind(&seq_string);
563   STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
564   STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
565   __ test(result, Immediate(kStringEncodingMask));
566   __ j(not_zero, &one_byte, Label::kNear);
567 
568   // Two-byte string.
569   // Load the two-byte character code into the result register.
570   __ movzx_w(result, FieldOperand(string,
571                                   index,
572                                   times_2,
573                                   SeqTwoByteString::kHeaderSize));
574   __ jmp(&done, Label::kNear);
575 
576   // One-byte string.
577   // Load the byte into the result register.
578   __ bind(&one_byte);
579   __ movzx_b(result, FieldOperand(string,
580                                   index,
581                                   times_1,
582                                   SeqOneByteString::kHeaderSize));
583   __ bind(&done);
584 }
585 
586 
587 #undef __
588 
589 
CodeAgingHelper(Isolate * isolate)590 CodeAgingHelper::CodeAgingHelper(Isolate* isolate) {
591   USE(isolate);
592   DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
593   CodePatcher patcher(isolate, young_sequence_.start(),
594                       young_sequence_.length());
595   patcher.masm()->push(ebp);
596   patcher.masm()->mov(ebp, esp);
597   patcher.masm()->push(esi);
598   patcher.masm()->push(edi);
599 }
600 
601 
602 #ifdef DEBUG
IsOld(byte * candidate) const603 bool CodeAgingHelper::IsOld(byte* candidate) const {
604   return *candidate == kCallOpcode;
605 }
606 #endif
607 
608 
IsYoungSequence(Isolate * isolate,byte * sequence)609 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
610   bool result = isolate->code_aging_helper()->IsYoung(sequence);
611   DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
612   return result;
613 }
614 
615 
GetCodeAgeAndParity(Isolate * isolate,byte * sequence,Age * age,MarkingParity * parity)616 void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
617                                MarkingParity* parity) {
618   if (IsYoungSequence(isolate, sequence)) {
619     *age = kNoAgeCodeAge;
620     *parity = NO_MARKING_PARITY;
621   } else {
622     sequence++;  // Skip the kCallOpcode byte
623     Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
624         Assembler::kCallTargetAddressOffset;
625     Code* stub = GetCodeFromTargetAddress(target_address);
626     GetCodeAgeAndParity(stub, age, parity);
627   }
628 }
629 
630 
PatchPlatformCodeAge(Isolate * isolate,byte * sequence,Code::Age age,MarkingParity parity)631 void Code::PatchPlatformCodeAge(Isolate* isolate,
632                                 byte* sequence,
633                                 Code::Age age,
634                                 MarkingParity parity) {
635   uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
636   if (age == kNoAgeCodeAge) {
637     isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
638     Assembler::FlushICache(isolate, sequence, young_length);
639   } else {
640     Code* stub = GetCodeAgeStub(isolate, age, parity);
641     CodePatcher patcher(isolate, sequence, young_length);
642     patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
643   }
644 }
645 
646 
647 }  // namespace internal
648 }  // namespace v8
649 
650 #endif  // V8_TARGET_ARCH_X87
651