1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_IA32_MACRO_ASSEMBLER_IA32_H_
29#define V8_IA32_MACRO_ASSEMBLER_IA32_H_
30
31#include "assembler.h"
32#include "frames.h"
33#include "v8globals.h"
34
35namespace v8 {
36namespace internal {
37
38// Flags used for the AllocateInNewSpace functions.
39enum AllocationFlags {
40  // No special flags.
41  NO_ALLOCATION_FLAGS = 0,
42  // Return the pointer to the allocated already tagged as a heap object.
43  TAG_OBJECT = 1 << 0,
44  // The content of the result register already contains the allocation top in
45  // new space.
46  RESULT_CONTAINS_TOP = 1 << 1
47};
48
49
50// Convenience for platform-independent signatures.  We do not normally
51// distinguish memory operands from other operands on ia32.
52typedef Operand MemOperand;
53
54enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
55enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
56
57
58bool AreAliased(Register r1, Register r2, Register r3, Register r4);
59
60
61// MacroAssembler implements a collection of frequently used macros.
62class MacroAssembler: public Assembler {
63 public:
64  // The isolate parameter can be NULL if the macro assembler should
65  // not use isolate-dependent functionality. In this case, it's the
66  // responsibility of the caller to never invoke such function on the
67  // macro assembler.
68  MacroAssembler(Isolate* isolate, void* buffer, int size);
69
70  // ---------------------------------------------------------------------------
71  // GC Support
72  enum RememberedSetFinalAction {
73    kReturnAtEnd,
74    kFallThroughAtEnd
75  };
76
77  // Record in the remembered set the fact that we have a pointer to new space
78  // at the address pointed to by the addr register.  Only works if addr is not
79  // in new space.
80  void RememberedSetHelper(Register object,  // Used for debug code.
81                           Register addr,
82                           Register scratch,
83                           SaveFPRegsMode save_fp,
84                           RememberedSetFinalAction and_then);
85
86  void CheckPageFlag(Register object,
87                     Register scratch,
88                     int mask,
89                     Condition cc,
90                     Label* condition_met,
91                     Label::Distance condition_met_distance = Label::kFar);
92
93  // Check if object is in new space.  Jumps if the object is not in new space.
94  // The register scratch can be object itself, but scratch will be clobbered.
95  void JumpIfNotInNewSpace(Register object,
96                           Register scratch,
97                           Label* branch,
98                           Label::Distance distance = Label::kFar) {
99    InNewSpace(object, scratch, zero, branch, distance);
100  }
101
102  // Check if object is in new space.  Jumps if the object is in new space.
103  // The register scratch can be object itself, but it will be clobbered.
104  void JumpIfInNewSpace(Register object,
105                        Register scratch,
106                        Label* branch,
107                        Label::Distance distance = Label::kFar) {
108    InNewSpace(object, scratch, not_zero, branch, distance);
109  }
110
111  // Check if an object has a given incremental marking color.  Also uses ecx!
112  void HasColor(Register object,
113                Register scratch0,
114                Register scratch1,
115                Label* has_color,
116                Label::Distance has_color_distance,
117                int first_bit,
118                int second_bit);
119
120  void JumpIfBlack(Register object,
121                   Register scratch0,
122                   Register scratch1,
123                   Label* on_black,
124                   Label::Distance on_black_distance = Label::kFar);
125
126  // Checks the color of an object.  If the object is already grey or black
127  // then we just fall through, since it is already live.  If it is white and
128  // we can determine that it doesn't need to be scanned, then we just mark it
129  // black and fall through.  For the rest we jump to the label so the
130  // incremental marker can fix its assumptions.
131  void EnsureNotWhite(Register object,
132                      Register scratch1,
133                      Register scratch2,
134                      Label* object_is_white_and_not_data,
135                      Label::Distance distance);
136
137  // Notify the garbage collector that we wrote a pointer into an object.
138  // |object| is the object being stored into, |value| is the object being
139  // stored.  value and scratch registers are clobbered by the operation.
140  // The offset is the offset from the start of the object, not the offset from
141  // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
142  void RecordWriteField(
143      Register object,
144      int offset,
145      Register value,
146      Register scratch,
147      SaveFPRegsMode save_fp,
148      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
149      SmiCheck smi_check = INLINE_SMI_CHECK);
150
151  // As above, but the offset has the tag presubtracted.  For use with
152  // Operand(reg, off).
153  void RecordWriteContextSlot(
154      Register context,
155      int offset,
156      Register value,
157      Register scratch,
158      SaveFPRegsMode save_fp,
159      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
160      SmiCheck smi_check = INLINE_SMI_CHECK) {
161    RecordWriteField(context,
162                     offset + kHeapObjectTag,
163                     value,
164                     scratch,
165                     save_fp,
166                     remembered_set_action,
167                     smi_check);
168  }
169
170  // Notify the garbage collector that we wrote a pointer into a fixed array.
171  // |array| is the array being stored into, |value| is the
172  // object being stored.  |index| is the array index represented as a
173  // Smi. All registers are clobbered by the operation RecordWriteArray
174  // filters out smis so it does not update the write barrier if the
175  // value is a smi.
176  void RecordWriteArray(
177      Register array,
178      Register value,
179      Register index,
180      SaveFPRegsMode save_fp,
181      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
182      SmiCheck smi_check = INLINE_SMI_CHECK);
183
184  // For page containing |object| mark region covering |address|
185  // dirty. |object| is the object being stored into, |value| is the
186  // object being stored. The address and value registers are clobbered by the
187  // operation. RecordWrite filters out smis so it does not update the
188  // write barrier if the value is a smi.
189  void RecordWrite(
190      Register object,
191      Register address,
192      Register value,
193      SaveFPRegsMode save_fp,
194      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
195      SmiCheck smi_check = INLINE_SMI_CHECK);
196
197#ifdef ENABLE_DEBUGGER_SUPPORT
198  // ---------------------------------------------------------------------------
199  // Debugger Support
200
201  void DebugBreak();
202#endif
203
204  // Enter specific kind of exit frame. Expects the number of
205  // arguments in register eax and sets up the number of arguments in
206  // register edi and the pointer to the first argument in register
207  // esi.
208  void EnterExitFrame(bool save_doubles);
209
210  void EnterApiExitFrame(int argc);
211
212  // Leave the current exit frame. Expects the return value in
213  // register eax:edx (untouched) and the pointer to the first
214  // argument in register esi.
215  void LeaveExitFrame(bool save_doubles);
216
217  // Leave the current exit frame. Expects the return value in
218  // register eax (untouched).
219  void LeaveApiExitFrame();
220
221  // Find the function context up the context chain.
222  void LoadContext(Register dst, int context_chain_length);
223
224  // Conditionally load the cached Array transitioned map of type
225  // transitioned_kind from the global context if the map in register
226  // map_in_out is the cached Array map in the global context of
227  // expected_kind.
228  void LoadTransitionedArrayMapConditional(
229      ElementsKind expected_kind,
230      ElementsKind transitioned_kind,
231      Register map_in_out,
232      Register scratch,
233      Label* no_map_match);
234
235  // Load the initial map for new Arrays from a JSFunction.
236  void LoadInitialArrayMap(Register function_in,
237                           Register scratch,
238                           Register map_out);
239
240  // Load the global function with the given index.
241  void LoadGlobalFunction(int index, Register function);
242
243  // Load the initial map from the global function. The registers
244  // function and map can be the same.
245  void LoadGlobalFunctionInitialMap(Register function, Register map);
246
247  // Push and pop the registers that can hold pointers.
248  void PushSafepointRegisters() { pushad(); }
249  void PopSafepointRegisters() { popad(); }
250  // Store the value in register/immediate src in the safepoint
251  // register stack slot for register dst.
252  void StoreToSafepointRegisterSlot(Register dst, Register src);
253  void StoreToSafepointRegisterSlot(Register dst, Immediate src);
254  void LoadFromSafepointRegisterSlot(Register dst, Register src);
255
256  void LoadHeapObject(Register result, Handle<HeapObject> object);
257  void PushHeapObject(Handle<HeapObject> object);
258
259  void LoadObject(Register result, Handle<Object> object) {
260    if (object->IsHeapObject()) {
261      LoadHeapObject(result, Handle<HeapObject>::cast(object));
262    } else {
263      Set(result, Immediate(object));
264    }
265  }
266
267  // ---------------------------------------------------------------------------
268  // JavaScript invokes
269
270  // Set up call kind marking in ecx. The method takes ecx as an
271  // explicit first parameter to make the code more readable at the
272  // call sites.
273  void SetCallKind(Register dst, CallKind kind);
274
275  // Invoke the JavaScript function code by either calling or jumping.
276  void InvokeCode(Register code,
277                  const ParameterCount& expected,
278                  const ParameterCount& actual,
279                  InvokeFlag flag,
280                  const CallWrapper& call_wrapper,
281                  CallKind call_kind) {
282    InvokeCode(Operand(code), expected, actual, flag, call_wrapper, call_kind);
283  }
284
285  void InvokeCode(const Operand& code,
286                  const ParameterCount& expected,
287                  const ParameterCount& actual,
288                  InvokeFlag flag,
289                  const CallWrapper& call_wrapper,
290                  CallKind call_kind);
291
292  void InvokeCode(Handle<Code> code,
293                  const ParameterCount& expected,
294                  const ParameterCount& actual,
295                  RelocInfo::Mode rmode,
296                  InvokeFlag flag,
297                  const CallWrapper& call_wrapper,
298                  CallKind call_kind);
299
300  // Invoke the JavaScript function in the given register. Changes the
301  // current context to the context in the function before invoking.
302  void InvokeFunction(Register function,
303                      const ParameterCount& actual,
304                      InvokeFlag flag,
305                      const CallWrapper& call_wrapper,
306                      CallKind call_kind);
307
308  void InvokeFunction(Handle<JSFunction> function,
309                      const ParameterCount& actual,
310                      InvokeFlag flag,
311                      const CallWrapper& call_wrapper,
312                      CallKind call_kind);
313
314  // Invoke specified builtin JavaScript function. Adds an entry to
315  // the unresolved list if the name does not resolve.
316  void InvokeBuiltin(Builtins::JavaScript id,
317                     InvokeFlag flag,
318                     const CallWrapper& call_wrapper = NullCallWrapper());
319
320  // Store the function for the given builtin in the target register.
321  void GetBuiltinFunction(Register target, Builtins::JavaScript id);
322
323  // Store the code object for the given builtin in the target register.
324  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
325
326  // Expression support
327  void Set(Register dst, const Immediate& x);
328  void Set(const Operand& dst, const Immediate& x);
329
330  // Support for constant splitting.
331  bool IsUnsafeImmediate(const Immediate& x);
332  void SafeSet(Register dst, const Immediate& x);
333  void SafePush(const Immediate& x);
334
335  // Compare against a known root, e.g. undefined, null, true, ...
336  void CompareRoot(Register with, Heap::RootListIndex index);
337  void CompareRoot(const Operand& with, Heap::RootListIndex index);
338
339  // Compare object type for heap object.
340  // Incoming register is heap_object and outgoing register is map.
341  void CmpObjectType(Register heap_object, InstanceType type, Register map);
342
343  // Compare instance type for map.
344  void CmpInstanceType(Register map, InstanceType type);
345
346  // Check if a map for a JSObject indicates that the object has fast elements.
347  // Jump to the specified label if it does not.
348  void CheckFastElements(Register map,
349                         Label* fail,
350                         Label::Distance distance = Label::kFar);
351
352  // Check if a map for a JSObject indicates that the object can have both smi
353  // and HeapObject elements.  Jump to the specified label if it does not.
354  void CheckFastObjectElements(Register map,
355                               Label* fail,
356                               Label::Distance distance = Label::kFar);
357
358  // Check if a map for a JSObject indicates that the object has fast smi only
359  // elements.  Jump to the specified label if it does not.
360  void CheckFastSmiOnlyElements(Register map,
361                                Label* fail,
362                                Label::Distance distance = Label::kFar);
363
364  // Check to see if maybe_number can be stored as a double in
365  // FastDoubleElements. If it can, store it at the index specified by key in
366  // the FastDoubleElements array elements, otherwise jump to fail.
367  void StoreNumberToDoubleElements(Register maybe_number,
368                                   Register elements,
369                                   Register key,
370                                   Register scratch1,
371                                   XMMRegister scratch2,
372                                   Label* fail,
373                                   bool specialize_for_processor);
374
375  // Compare an object's map with the specified map and its transitioned
376  // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. FLAGS are set with
377  // result of map compare. If multiple map compares are required, the compare
378  // sequences branches to early_success.
379  void CompareMap(Register obj,
380                  Handle<Map> map,
381                  Label* early_success,
382                  CompareMapMode mode = REQUIRE_EXACT_MAP);
383
384  // Check if the map of an object is equal to a specified map and branch to
385  // label if not. Skip the smi check if not required (object is known to be a
386  // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
387  // against maps that are ElementsKind transition maps of the specified map.
388  void CheckMap(Register obj,
389                Handle<Map> map,
390                Label* fail,
391                SmiCheckType smi_check_type,
392                CompareMapMode mode = REQUIRE_EXACT_MAP);
393
394  // Check if the map of an object is equal to a specified map and branch to a
395  // specified target if equal. Skip the smi check if not required (object is
396  // known to be a heap object)
397  void DispatchMap(Register obj,
398                   Handle<Map> map,
399                   Handle<Code> success,
400                   SmiCheckType smi_check_type);
401
402  // Check if the object in register heap_object is a string. Afterwards the
403  // register map contains the object map and the register instance_type
404  // contains the instance_type. The registers map and instance_type can be the
405  // same in which case it contains the instance type afterwards. Either of the
406  // registers map and instance_type can be the same as heap_object.
407  Condition IsObjectStringType(Register heap_object,
408                               Register map,
409                               Register instance_type);
410
411  // Check if a heap object's type is in the JSObject range, not including
412  // JSFunction.  The object's map will be loaded in the map register.
413  // Any or all of the three registers may be the same.
414  // The contents of the scratch register will always be overwritten.
415  void IsObjectJSObjectType(Register heap_object,
416                            Register map,
417                            Register scratch,
418                            Label* fail);
419
420  // The contents of the scratch register will be overwritten.
421  void IsInstanceJSObjectType(Register map, Register scratch, Label* fail);
422
423  // FCmp is similar to integer cmp, but requires unsigned
424  // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
425  void FCmp();
426
427  void ClampUint8(Register reg);
428
429  void ClampDoubleToUint8(XMMRegister input_reg,
430                          XMMRegister scratch_reg,
431                          Register result_reg);
432
433
434  // Smi tagging support.
435  void SmiTag(Register reg) {
436    STATIC_ASSERT(kSmiTag == 0);
437    STATIC_ASSERT(kSmiTagSize == 1);
438    add(reg, reg);
439  }
440  void SmiUntag(Register reg) {
441    sar(reg, kSmiTagSize);
442  }
443
444  // Modifies the register even if it does not contain a Smi!
445  void SmiUntag(Register reg, Label* is_smi) {
446    STATIC_ASSERT(kSmiTagSize == 1);
447    sar(reg, kSmiTagSize);
448    STATIC_ASSERT(kSmiTag == 0);
449    j(not_carry, is_smi);
450  }
451
452  // Jump the register contains a smi.
453  inline void JumpIfSmi(Register value,
454                        Label* smi_label,
455                        Label::Distance distance = Label::kFar) {
456    test(value, Immediate(kSmiTagMask));
457    j(zero, smi_label, distance);
458  }
459  // Jump if the operand is a smi.
460  inline void JumpIfSmi(Operand value,
461                        Label* smi_label,
462                        Label::Distance distance = Label::kFar) {
463    test(value, Immediate(kSmiTagMask));
464    j(zero, smi_label, distance);
465  }
466  // Jump if register contain a non-smi.
467  inline void JumpIfNotSmi(Register value,
468                           Label* not_smi_label,
469                           Label::Distance distance = Label::kFar) {
470    test(value, Immediate(kSmiTagMask));
471    j(not_zero, not_smi_label, distance);
472  }
473
474  void LoadInstanceDescriptors(Register map, Register descriptors);
475
476  void LoadPowerOf2(XMMRegister dst, Register scratch, int power);
477
478  // Abort execution if argument is not a number. Used in debug code.
479  void AbortIfNotNumber(Register object);
480
481  // Abort execution if argument is not a smi. Used in debug code.
482  void AbortIfNotSmi(Register object);
483
484  // Abort execution if argument is a smi. Used in debug code.
485  void AbortIfSmi(Register object);
486
487  // Abort execution if argument is a string. Used in debug code.
488  void AbortIfNotString(Register object);
489
490  // ---------------------------------------------------------------------------
491  // Exception handling
492
493  // Push a new try handler and link it into try handler chain.
494  void PushTryHandler(StackHandler::Kind kind, int handler_index);
495
496  // Unlink the stack handler on top of the stack from the try handler chain.
497  void PopTryHandler();
498
499  // Throw to the top handler in the try hander chain.
500  void Throw(Register value);
501
502  // Throw past all JS frames to the top JS entry frame.
503  void ThrowUncatchable(Register value);
504
505  // ---------------------------------------------------------------------------
506  // Inline caching support
507
508  // Generate code for checking access rights - used for security checks
509  // on access to global objects across environments. The holder register
510  // is left untouched, but the scratch register is clobbered.
511  void CheckAccessGlobalProxy(Register holder_reg,
512                              Register scratch,
513                              Label* miss);
514
515  void GetNumberHash(Register r0, Register scratch);
516
517  void LoadFromNumberDictionary(Label* miss,
518                                Register elements,
519                                Register key,
520                                Register r0,
521                                Register r1,
522                                Register r2,
523                                Register result);
524
525
526  // ---------------------------------------------------------------------------
527  // Allocation support
528
529  // Allocate an object in new space. If the new space is exhausted control
530  // continues at the gc_required label. The allocated object is returned in
531  // result and end of the new object is returned in result_end. The register
532  // scratch can be passed as no_reg in which case an additional object
533  // reference will be added to the reloc info. The returned pointers in result
534  // and result_end have not yet been tagged as heap objects. If
535  // result_contains_top_on_entry is true the content of result is known to be
536  // the allocation top on entry (could be result_end from a previous call to
537  // AllocateInNewSpace). If result_contains_top_on_entry is true scratch
538  // should be no_reg as it is never used.
539  void AllocateInNewSpace(int object_size,
540                          Register result,
541                          Register result_end,
542                          Register scratch,
543                          Label* gc_required,
544                          AllocationFlags flags);
545
546  void AllocateInNewSpace(int header_size,
547                          ScaleFactor element_size,
548                          Register element_count,
549                          Register result,
550                          Register result_end,
551                          Register scratch,
552                          Label* gc_required,
553                          AllocationFlags flags);
554
555  void AllocateInNewSpace(Register object_size,
556                          Register result,
557                          Register result_end,
558                          Register scratch,
559                          Label* gc_required,
560                          AllocationFlags flags);
561
562  // Undo allocation in new space. The object passed and objects allocated after
563  // it will no longer be allocated. Make sure that no pointers are left to the
564  // object(s) no longer allocated as they would be invalid when allocation is
565  // un-done.
566  void UndoAllocationInNewSpace(Register object);
567
568  // Allocate a heap number in new space with undefined value. The
569  // register scratch2 can be passed as no_reg; the others must be
570  // valid registers. Returns tagged pointer in result register, or
571  // jumps to gc_required if new space is full.
572  void AllocateHeapNumber(Register result,
573                          Register scratch1,
574                          Register scratch2,
575                          Label* gc_required);
576
577  // Allocate a sequential string. All the header fields of the string object
578  // are initialized.
579  void AllocateTwoByteString(Register result,
580                             Register length,
581                             Register scratch1,
582                             Register scratch2,
583                             Register scratch3,
584                             Label* gc_required);
585  void AllocateAsciiString(Register result,
586                           Register length,
587                           Register scratch1,
588                           Register scratch2,
589                           Register scratch3,
590                           Label* gc_required);
591  void AllocateAsciiString(Register result,
592                           int length,
593                           Register scratch1,
594                           Register scratch2,
595                           Label* gc_required);
596
597  // Allocate a raw cons string object. Only the map field of the result is
598  // initialized.
599  void AllocateTwoByteConsString(Register result,
600                          Register scratch1,
601                          Register scratch2,
602                          Label* gc_required);
603  void AllocateAsciiConsString(Register result,
604                               Register scratch1,
605                               Register scratch2,
606                               Label* gc_required);
607
608  // Allocate a raw sliced string object. Only the map field of the result is
609  // initialized.
610  void AllocateTwoByteSlicedString(Register result,
611                            Register scratch1,
612                            Register scratch2,
613                            Label* gc_required);
614  void AllocateAsciiSlicedString(Register result,
615                                 Register scratch1,
616                                 Register scratch2,
617                                 Label* gc_required);
618
619  // Copy memory, byte-by-byte, from source to destination.  Not optimized for
620  // long or aligned copies.
621  // The contents of index and scratch are destroyed.
622  void CopyBytes(Register source,
623                 Register destination,
624                 Register length,
625                 Register scratch);
626
627  // Initialize fields with filler values.  Fields starting at |start_offset|
628  // not including end_offset are overwritten with the value in |filler|.  At
629  // the end the loop, |start_offset| takes the value of |end_offset|.
630  void InitializeFieldsWithFiller(Register start_offset,
631                                  Register end_offset,
632                                  Register filler);
633
634  // ---------------------------------------------------------------------------
635  // Support functions.
636
637  // Check a boolean-bit of a Smi field.
638  void BooleanBitTest(Register object, int field_offset, int bit_index);
639
640  // Check if result is zero and op is negative.
641  void NegativeZeroTest(Register result, Register op, Label* then_label);
642
643  // Check if result is zero and any of op1 and op2 are negative.
644  // Register scratch is destroyed, and it must be different from op2.
645  void NegativeZeroTest(Register result, Register op1, Register op2,
646                        Register scratch, Label* then_label);
647
648  // Try to get function prototype of a function and puts the value in
649  // the result register. Checks that the function really is a
650  // function and jumps to the miss label if the fast checks fail. The
651  // function register will be untouched; the other registers may be
652  // clobbered.
653  void TryGetFunctionPrototype(Register function,
654                               Register result,
655                               Register scratch,
656                               Label* miss,
657                               bool miss_on_bound_function = false);
658
659  // Generates code for reporting that an illegal operation has
660  // occurred.
661  void IllegalOperation(int num_arguments);
662
663  // Picks out an array index from the hash field.
664  // Register use:
665  //   hash - holds the index's hash. Clobbered.
666  //   index - holds the overwritten index on exit.
667  void IndexFromHash(Register hash, Register index);
668
669  // ---------------------------------------------------------------------------
670  // Runtime calls
671
672  // Call a code stub.  Generate the code if necessary.
673  void CallStub(CodeStub* stub, unsigned ast_id = kNoASTId);
674
675  // Tail call a code stub (jump).  Generate the code if necessary.
676  void TailCallStub(CodeStub* stub);
677
678  // Return from a code stub after popping its arguments.
679  void StubReturn(int argc);
680
681  // Call a runtime routine.
682  void CallRuntime(const Runtime::Function* f, int num_arguments);
683  void CallRuntimeSaveDoubles(Runtime::FunctionId id);
684
685  // Convenience function: Same as above, but takes the fid instead.
686  void CallRuntime(Runtime::FunctionId id, int num_arguments);
687
688  // Convenience function: call an external reference.
689  void CallExternalReference(ExternalReference ref, int num_arguments);
690
691  // Tail call of a runtime routine (jump).
692  // Like JumpToExternalReference, but also takes care of passing the number
693  // of parameters.
694  void TailCallExternalReference(const ExternalReference& ext,
695                                 int num_arguments,
696                                 int result_size);
697
698  // Convenience function: tail call a runtime routine (jump).
699  void TailCallRuntime(Runtime::FunctionId fid,
700                       int num_arguments,
701                       int result_size);
702
703  // Before calling a C-function from generated code, align arguments on stack.
704  // After aligning the frame, arguments must be stored in esp[0], esp[4],
705  // etc., not pushed. The argument count assumes all arguments are word sized.
706  // Some compilers/platforms require the stack to be aligned when calling
707  // C++ code.
708  // Needs a scratch register to do some arithmetic. This register will be
709  // trashed.
710  void PrepareCallCFunction(int num_arguments, Register scratch);
711
712  // Calls a C function and cleans up the space for arguments allocated
713  // by PrepareCallCFunction. The called function is not allowed to trigger a
714  // garbage collection, since that might move the code and invalidate the
715  // return address (unless this is somehow accounted for by the called
716  // function).
717  void CallCFunction(ExternalReference function, int num_arguments);
718  void CallCFunction(Register function, int num_arguments);
719
720  // Prepares stack to put arguments (aligns and so on). Reserves
721  // space for return value if needed (assumes the return value is a handle).
722  // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1)
723  // etc. Saves context (esi). If space was reserved for return value then
724  // stores the pointer to the reserved slot into esi.
725  void PrepareCallApiFunction(int argc);
726
727  // Calls an API function.  Allocates HandleScope, extracts returned value
728  // from handle and propagates exceptions.  Clobbers ebx, edi and
729  // caller-save registers.  Restores context.  On return removes
730  // stack_space * kPointerSize (GCed).
731  void CallApiFunctionAndReturn(Address function_address, int stack_space);
732
733  // Jump to a runtime routine.
734  void JumpToExternalReference(const ExternalReference& ext);
735
736  // ---------------------------------------------------------------------------
737  // Utilities
738
739  void Ret();
740
741  // Return and drop arguments from stack, where the number of arguments
742  // may be bigger than 2^16 - 1.  Requires a scratch register.
743  void Ret(int bytes_dropped, Register scratch);
744
745  // Emit code to discard a non-negative number of pointer-sized elements
746  // from the stack, clobbering only the esp register.
747  void Drop(int element_count);
748
749  void Call(Label* target) { call(target); }
750
751  // Emit call to the code we are currently generating.
752  void CallSelf() {
753    Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
754    call(self, RelocInfo::CODE_TARGET);
755  }
756
757  // Move if the registers are not identical.
758  void Move(Register target, Register source);
759
760  // Push a handle value.
761  void Push(Handle<Object> handle) { push(Immediate(handle)); }
762
763  Handle<Object> CodeObject() {
764    ASSERT(!code_object_.is_null());
765    return code_object_;
766  }
767
768
769  // ---------------------------------------------------------------------------
770  // StatsCounter support
771
772  void SetCounter(StatsCounter* counter, int value);
773  void IncrementCounter(StatsCounter* counter, int value);
774  void DecrementCounter(StatsCounter* counter, int value);
775  void IncrementCounter(Condition cc, StatsCounter* counter, int value);
776  void DecrementCounter(Condition cc, StatsCounter* counter, int value);
777
778
779  // ---------------------------------------------------------------------------
780  // Debugging
781
782  // Calls Abort(msg) if the condition cc is not satisfied.
783  // Use --debug_code to enable.
784  void Assert(Condition cc, const char* msg);
785
786  void AssertFastElements(Register elements);
787
788  // Like Assert(), but always enabled.
789  void Check(Condition cc, const char* msg);
790
791  // Print a message to stdout and abort execution.
792  void Abort(const char* msg);
793
794  // Check that the stack is aligned.
795  void CheckStackAlignment();
796
797  // Verify restrictions about code generated in stubs.
798  void set_generating_stub(bool value) { generating_stub_ = value; }
799  bool generating_stub() { return generating_stub_; }
800  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
801  bool allow_stub_calls() { return allow_stub_calls_; }
802  void set_has_frame(bool value) { has_frame_ = value; }
803  bool has_frame() { return has_frame_; }
804  inline bool AllowThisStubCall(CodeStub* stub);
805
806  // ---------------------------------------------------------------------------
807  // String utilities.
808
809  // Check whether the instance type represents a flat ASCII string. Jump to the
810  // label if not. If the instance type can be scratched specify same register
811  // for both instance type and scratch.
812  void JumpIfInstanceTypeIsNotSequentialAscii(Register instance_type,
813                                              Register scratch,
814                                              Label* on_not_flat_ascii_string);
815
816  // Checks if both objects are sequential ASCII strings, and jumps to label
817  // if either is not.
818  void JumpIfNotBothSequentialAsciiStrings(Register object1,
819                                           Register object2,
820                                           Register scratch1,
821                                           Register scratch2,
822                                           Label* on_not_flat_ascii_strings);
823
824  static int SafepointRegisterStackIndex(Register reg) {
825    return SafepointRegisterStackIndex(reg.code());
826  }
827
828  // Activation support.
829  void EnterFrame(StackFrame::Type type);
830  void LeaveFrame(StackFrame::Type type);
831
832  // Expects object in eax and returns map with validated enum cache
833  // in eax.  Assumes that any other register can be used as a scratch.
834  void CheckEnumCache(Label* call_runtime);
835
836 private:
837  bool generating_stub_;
838  bool allow_stub_calls_;
839  bool has_frame_;
840  // This handle will be patched with the code object on installation.
841  Handle<Object> code_object_;
842
843  // Helper functions for generating invokes.
844  void InvokePrologue(const ParameterCount& expected,
845                      const ParameterCount& actual,
846                      Handle<Code> code_constant,
847                      const Operand& code_operand,
848                      Label* done,
849                      bool* definitely_mismatches,
850                      InvokeFlag flag,
851                      Label::Distance done_distance,
852                      const CallWrapper& call_wrapper = NullCallWrapper(),
853                      CallKind call_kind = CALL_AS_METHOD);
854
855  void EnterExitFramePrologue();
856  void EnterExitFrameEpilogue(int argc, bool save_doubles);
857
858  void LeaveExitFrameEpilogue();
859
860  // Allocation support helpers.
861  void LoadAllocationTopHelper(Register result,
862                               Register scratch,
863                               AllocationFlags flags);
864  void UpdateAllocationTopHelper(Register result_end, Register scratch);
865
866  // Helper for PopHandleScope.  Allowed to perform a GC and returns
867  // NULL if gc_allowed.  Does not perform a GC if !gc_allowed, and
868  // possibly returns a failure object indicating an allocation failure.
869  MUST_USE_RESULT MaybeObject* PopHandleScopeHelper(Register saved,
870                                                    Register scratch,
871                                                    bool gc_allowed);
872
873  // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
874  void InNewSpace(Register object,
875                  Register scratch,
876                  Condition cc,
877                  Label* condition_met,
878                  Label::Distance condition_met_distance = Label::kFar);
879
880  // Helper for finding the mark bits for an address.  Afterwards, the
881  // bitmap register points at the word with the mark bits and the mask
882  // the position of the first bit.  Uses ecx as scratch and leaves addr_reg
883  // unchanged.
884  inline void GetMarkBits(Register addr_reg,
885                          Register bitmap_reg,
886                          Register mask_reg);
887
888  // Helper for throwing exceptions.  Compute a handler address and jump to
889  // it.  See the implementation for register usage.
890  void JumpToHandlerEntry();
891
892  // Compute memory operands for safepoint stack slots.
893  Operand SafepointRegisterSlot(Register reg);
894  static int SafepointRegisterStackIndex(int reg_code);
895
896  // Needs access to SafepointRegisterStackIndex for optimized frame
897  // traversal.
898  friend class OptimizedFrame;
899};
900
901
902// The code patcher is used to patch (typically) small parts of code e.g. for
903// debugging and other types of instrumentation. When using the code patcher
904// the exact number of bytes specified must be emitted. Is not legal to emit
905// relocation information. If any of these constraints are violated it causes
906// an assertion.
907class CodePatcher {
908 public:
909  CodePatcher(byte* address, int size);
910  virtual ~CodePatcher();
911
912  // Macro assembler to emit code.
913  MacroAssembler* masm() { return &masm_; }
914
915 private:
916  byte* address_;  // The address of the code being patched.
917  int size_;  // Number of bytes of the expected patch size.
918  MacroAssembler masm_;  // Macro assembler used to generate the code.
919};
920
921
922// -----------------------------------------------------------------------------
923// Static helper functions.
924
925// Generate an Operand for loading a field from an object.
926inline Operand FieldOperand(Register object, int offset) {
927  return Operand(object, offset - kHeapObjectTag);
928}
929
930
931// Generate an Operand for loading an indexed field from an object.
932inline Operand FieldOperand(Register object,
933                            Register index,
934                            ScaleFactor scale,
935                            int offset) {
936  return Operand(object, index, scale, offset - kHeapObjectTag);
937}
938
939
940inline Operand ContextOperand(Register context, int index) {
941  return Operand(context, Context::SlotOffset(index));
942}
943
944
945inline Operand GlobalObjectOperand() {
946  return ContextOperand(esi, Context::GLOBAL_INDEX);
947}
948
949
950// Generates an Operand for saving parameters after PrepareCallApiFunction.
951Operand ApiParameterOperand(int index);
952
953
954#ifdef GENERATED_CODE_COVERAGE
955extern void LogGeneratedCodeCoverage(const char* file_line);
956#define CODE_COVERAGE_STRINGIFY(x) #x
957#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
958#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
959#define ACCESS_MASM(masm) {                                               \
960    byte* ia32_coverage_function =                                        \
961        reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
962    masm->pushfd();                                                       \
963    masm->pushad();                                                       \
964    masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__)));         \
965    masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY);         \
966    masm->pop(eax);                                                       \
967    masm->popad();                                                        \
968    masm->popfd();                                                        \
969  }                                                                       \
970  masm->
971#else
972#define ACCESS_MASM(masm) masm->
973#endif
974
975
976} }  // namespace v8::internal
977
978#endif  // V8_IA32_MACRO_ASSEMBLER_IA32_H_
979