Home | History | Annotate | Download | only in ia32
      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 #ifndef V8_IA32_MACRO_ASSEMBLER_IA32_H_
      6 #define V8_IA32_MACRO_ASSEMBLER_IA32_H_
      7 
      8 #include "src/assembler.h"
      9 #include "src/bailout-reason.h"
     10 #include "src/frames.h"
     11 #include "src/globals.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 // Give alias names to registers for calling conventions.
     17 const Register kReturnRegister0 = {Register::kCode_eax};
     18 const Register kReturnRegister1 = {Register::kCode_edx};
     19 const Register kJSFunctionRegister = {Register::kCode_edi};
     20 const Register kContextRegister = {Register::kCode_esi};
     21 const Register kInterpreterAccumulatorRegister = {Register::kCode_eax};
     22 const Register kInterpreterRegisterFileRegister = {Register::kCode_edx};
     23 const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_ecx};
     24 const Register kInterpreterBytecodeArrayRegister = {Register::kCode_edi};
     25 const Register kJavaScriptCallArgCountRegister = {Register::kCode_eax};
     26 const Register kJavaScriptCallNewTargetRegister = {Register::kCode_edx};
     27 const Register kRuntimeCallFunctionRegister = {Register::kCode_ebx};
     28 const Register kRuntimeCallArgCountRegister = {Register::kCode_eax};
     29 
     30 // Spill slots used by interpreter dispatch calling convention.
     31 const int kInterpreterDispatchTableSpillSlot = -1;
     32 
     33 // Convenience for platform-independent signatures.  We do not normally
     34 // distinguish memory operands from other operands on ia32.
     35 typedef Operand MemOperand;
     36 
     37 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
     38 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
     39 enum PointersToHereCheck {
     40   kPointersToHereMaybeInteresting,
     41   kPointersToHereAreAlwaysInteresting
     42 };
     43 
     44 enum RegisterValueType { REGISTER_VALUE_IS_SMI, REGISTER_VALUE_IS_INT32 };
     45 
     46 #ifdef DEBUG
     47 bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg,
     48                 Register reg4 = no_reg, Register reg5 = no_reg,
     49                 Register reg6 = no_reg, Register reg7 = no_reg,
     50                 Register reg8 = no_reg);
     51 #endif
     52 
     53 // MacroAssembler implements a collection of frequently used macros.
     54 class MacroAssembler: public Assembler {
     55  public:
     56   MacroAssembler(Isolate* isolate, void* buffer, int size,
     57                  CodeObjectRequired create_code_object);
     58 
     59   void Load(Register dst, const Operand& src, Representation r);
     60   void Store(Register src, const Operand& dst, Representation r);
     61 
     62   // Load a register with a long value as efficiently as possible.
     63   void Set(Register dst, int32_t x) {
     64     if (x == 0) {
     65       xor_(dst, dst);
     66     } else {
     67       mov(dst, Immediate(x));
     68     }
     69   }
     70   void Set(const Operand& dst, int32_t x) { mov(dst, Immediate(x)); }
     71 
     72   // Operations on roots in the root-array.
     73   void LoadRoot(Register destination, Heap::RootListIndex index);
     74   void StoreRoot(Register source, Register scratch, Heap::RootListIndex index);
     75   void CompareRoot(Register with, Register scratch, Heap::RootListIndex index);
     76   // These methods can only be used with constant roots (i.e. non-writable
     77   // and not in new space).
     78   void CompareRoot(Register with, Heap::RootListIndex index);
     79   void CompareRoot(const Operand& with, Heap::RootListIndex index);
     80   void PushRoot(Heap::RootListIndex index);
     81 
     82   // Compare the object in a register to a value and jump if they are equal.
     83   void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal,
     84                   Label::Distance if_equal_distance = Label::kFar) {
     85     CompareRoot(with, index);
     86     j(equal, if_equal, if_equal_distance);
     87   }
     88   void JumpIfRoot(const Operand& with, Heap::RootListIndex index,
     89                   Label* if_equal,
     90                   Label::Distance if_equal_distance = Label::kFar) {
     91     CompareRoot(with, index);
     92     j(equal, if_equal, if_equal_distance);
     93   }
     94 
     95   // Compare the object in a register to a value and jump if they are not equal.
     96   void JumpIfNotRoot(Register with, Heap::RootListIndex index,
     97                      Label* if_not_equal,
     98                      Label::Distance if_not_equal_distance = Label::kFar) {
     99     CompareRoot(with, index);
    100     j(not_equal, if_not_equal, if_not_equal_distance);
    101   }
    102   void JumpIfNotRoot(const Operand& with, Heap::RootListIndex index,
    103                      Label* if_not_equal,
    104                      Label::Distance if_not_equal_distance = Label::kFar) {
    105     CompareRoot(with, index);
    106     j(not_equal, if_not_equal, if_not_equal_distance);
    107   }
    108 
    109   // ---------------------------------------------------------------------------
    110   // GC Support
    111   enum RememberedSetFinalAction { kReturnAtEnd, kFallThroughAtEnd };
    112 
    113   // Record in the remembered set the fact that we have a pointer to new space
    114   // at the address pointed to by the addr register.  Only works if addr is not
    115   // in new space.
    116   void RememberedSetHelper(Register object,  // Used for debug code.
    117                            Register addr, Register scratch,
    118                            SaveFPRegsMode save_fp,
    119                            RememberedSetFinalAction and_then);
    120 
    121   void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
    122                      Label* condition_met,
    123                      Label::Distance condition_met_distance = Label::kFar);
    124 
    125   void CheckPageFlagForMap(
    126       Handle<Map> map, int mask, Condition cc, Label* condition_met,
    127       Label::Distance condition_met_distance = Label::kFar);
    128 
    129   // Check if object is in new space.  Jumps if the object is not in new space.
    130   // The register scratch can be object itself, but scratch will be clobbered.
    131   void JumpIfNotInNewSpace(Register object, Register scratch, Label* branch,
    132                            Label::Distance distance = Label::kFar) {
    133     InNewSpace(object, scratch, zero, branch, distance);
    134   }
    135 
    136   // Check if object is in new space.  Jumps if the object is in new space.
    137   // The register scratch can be object itself, but it will be clobbered.
    138   void JumpIfInNewSpace(Register object, Register scratch, Label* branch,
    139                         Label::Distance distance = Label::kFar) {
    140     InNewSpace(object, scratch, not_zero, branch, distance);
    141   }
    142 
    143   // Check if an object has a given incremental marking color.  Also uses ecx!
    144   void HasColor(Register object, Register scratch0, Register scratch1,
    145                 Label* has_color, Label::Distance has_color_distance,
    146                 int first_bit, int second_bit);
    147 
    148   void JumpIfBlack(Register object, Register scratch0, Register scratch1,
    149                    Label* on_black,
    150                    Label::Distance on_black_distance = Label::kFar);
    151 
    152   // Checks the color of an object.  If the object is white we jump to the
    153   // incremental marker.
    154   void JumpIfWhite(Register value, Register scratch1, Register scratch2,
    155                    Label* value_is_white, Label::Distance distance);
    156 
    157   // Notify the garbage collector that we wrote a pointer into an object.
    158   // |object| is the object being stored into, |value| is the object being
    159   // stored.  value and scratch registers are clobbered by the operation.
    160   // The offset is the offset from the start of the object, not the offset from
    161   // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
    162   void RecordWriteField(
    163       Register object, int offset, Register value, Register scratch,
    164       SaveFPRegsMode save_fp,
    165       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
    166       SmiCheck smi_check = INLINE_SMI_CHECK,
    167       PointersToHereCheck pointers_to_here_check_for_value =
    168           kPointersToHereMaybeInteresting);
    169 
    170   // As above, but the offset has the tag presubtracted.  For use with
    171   // Operand(reg, off).
    172   void RecordWriteContextSlot(
    173       Register context, int offset, Register value, Register scratch,
    174       SaveFPRegsMode save_fp,
    175       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
    176       SmiCheck smi_check = INLINE_SMI_CHECK,
    177       PointersToHereCheck pointers_to_here_check_for_value =
    178           kPointersToHereMaybeInteresting) {
    179     RecordWriteField(context, offset + kHeapObjectTag, value, scratch, save_fp,
    180                      remembered_set_action, smi_check,
    181                      pointers_to_here_check_for_value);
    182   }
    183 
    184   // Notify the garbage collector that we wrote a pointer into a fixed array.
    185   // |array| is the array being stored into, |value| is the
    186   // object being stored.  |index| is the array index represented as a
    187   // Smi. All registers are clobbered by the operation RecordWriteArray
    188   // filters out smis so it does not update the write barrier if the
    189   // value is a smi.
    190   void RecordWriteArray(
    191       Register array, Register value, Register index, SaveFPRegsMode save_fp,
    192       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
    193       SmiCheck smi_check = INLINE_SMI_CHECK,
    194       PointersToHereCheck pointers_to_here_check_for_value =
    195           kPointersToHereMaybeInteresting);
    196 
    197   // For page containing |object| mark region covering |address|
    198   // dirty. |object| is the object being stored into, |value| is the
    199   // object being stored. The address and value registers are clobbered by the
    200   // operation. RecordWrite filters out smis so it does not update the
    201   // write barrier if the value is a smi.
    202   void RecordWrite(
    203       Register object, Register address, Register value, SaveFPRegsMode save_fp,
    204       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
    205       SmiCheck smi_check = INLINE_SMI_CHECK,
    206       PointersToHereCheck pointers_to_here_check_for_value =
    207           kPointersToHereMaybeInteresting);
    208 
    209   // For page containing |object| mark the region covering the object's map
    210   // dirty. |object| is the object being stored into, |map| is the Map object
    211   // that was stored.
    212   void RecordWriteForMap(Register object, Handle<Map> map, Register scratch1,
    213                          Register scratch2, SaveFPRegsMode save_fp);
    214 
    215   // ---------------------------------------------------------------------------
    216   // Debugger Support
    217 
    218   void DebugBreak();
    219 
    220   // Generates function and stub prologue code.
    221   void StubPrologue();
    222   void Prologue(bool code_pre_aging);
    223 
    224   // Enter specific kind of exit frame. Expects the number of
    225   // arguments in register eax and sets up the number of arguments in
    226   // register edi and the pointer to the first argument in register
    227   // esi.
    228   void EnterExitFrame(bool save_doubles);
    229 
    230   void EnterApiExitFrame(int argc);
    231 
    232   // Leave the current exit frame. Expects the return value in
    233   // register eax:edx (untouched) and the pointer to the first
    234   // argument in register esi (if pop_arguments == true).
    235   void LeaveExitFrame(bool save_doubles, bool pop_arguments = true);
    236 
    237   // Leave the current exit frame. Expects the return value in
    238   // register eax (untouched).
    239   void LeaveApiExitFrame(bool restore_context);
    240 
    241   // Find the function context up the context chain.
    242   void LoadContext(Register dst, int context_chain_length);
    243 
    244   // Load the global proxy from the current context.
    245   void LoadGlobalProxy(Register dst);
    246 
    247   // Conditionally load the cached Array transitioned map of type
    248   // transitioned_kind from the native context if the map in register
    249   // map_in_out is the cached Array map in the native context of
    250   // expected_kind.
    251   void LoadTransitionedArrayMapConditional(ElementsKind expected_kind,
    252                                            ElementsKind transitioned_kind,
    253                                            Register map_in_out,
    254                                            Register scratch,
    255                                            Label* no_map_match);
    256 
    257   // Load the global function with the given index.
    258   void LoadGlobalFunction(int index, Register function);
    259 
    260   // Load the initial map from the global function. The registers
    261   // function and map can be the same.
    262   void LoadGlobalFunctionInitialMap(Register function, Register map);
    263 
    264   // Push and pop the registers that can hold pointers.
    265   void PushSafepointRegisters() { pushad(); }
    266   void PopSafepointRegisters() { popad(); }
    267   // Store the value in register/immediate src in the safepoint
    268   // register stack slot for register dst.
    269   void StoreToSafepointRegisterSlot(Register dst, Register src);
    270   void StoreToSafepointRegisterSlot(Register dst, Immediate src);
    271   void LoadFromSafepointRegisterSlot(Register dst, Register src);
    272 
    273   void LoadHeapObject(Register result, Handle<HeapObject> object);
    274   void CmpHeapObject(Register reg, Handle<HeapObject> object);
    275   void PushHeapObject(Handle<HeapObject> object);
    276 
    277   void LoadObject(Register result, Handle<Object> object) {
    278     AllowDeferredHandleDereference heap_object_check;
    279     if (object->IsHeapObject()) {
    280       LoadHeapObject(result, Handle<HeapObject>::cast(object));
    281     } else {
    282       Move(result, Immediate(object));
    283     }
    284   }
    285 
    286   void CmpObject(Register reg, Handle<Object> object) {
    287     AllowDeferredHandleDereference heap_object_check;
    288     if (object->IsHeapObject()) {
    289       CmpHeapObject(reg, Handle<HeapObject>::cast(object));
    290     } else {
    291       cmp(reg, Immediate(object));
    292     }
    293   }
    294 
    295   // Compare the given value and the value of weak cell.
    296   void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
    297 
    298   void GetWeakValue(Register value, Handle<WeakCell> cell);
    299 
    300   // Load the value of the weak cell in the value register. Branch to the given
    301   // miss label if the weak cell was cleared.
    302   void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
    303 
    304   // ---------------------------------------------------------------------------
    305   // JavaScript invokes
    306 
    307   // Invoke the JavaScript function code by either calling or jumping.
    308 
    309   void InvokeFunctionCode(Register function, Register new_target,
    310                           const ParameterCount& expected,
    311                           const ParameterCount& actual, InvokeFlag flag,
    312                           const CallWrapper& call_wrapper);
    313 
    314   void FloodFunctionIfStepping(Register fun, Register new_target,
    315                                const ParameterCount& expected,
    316                                const ParameterCount& actual);
    317 
    318   // Invoke the JavaScript function in the given register. Changes the
    319   // current context to the context in the function before invoking.
    320   void InvokeFunction(Register function, Register new_target,
    321                       const ParameterCount& actual, InvokeFlag flag,
    322                       const CallWrapper& call_wrapper);
    323 
    324   void InvokeFunction(Register function, const ParameterCount& expected,
    325                       const ParameterCount& actual, InvokeFlag flag,
    326                       const CallWrapper& call_wrapper);
    327 
    328   void InvokeFunction(Handle<JSFunction> function,
    329                       const ParameterCount& expected,
    330                       const ParameterCount& actual, InvokeFlag flag,
    331                       const CallWrapper& call_wrapper);
    332 
    333   // Invoke specified builtin JavaScript function.
    334   void InvokeBuiltin(int native_context_index, InvokeFlag flag,
    335                      const CallWrapper& call_wrapper = NullCallWrapper());
    336 
    337   // Store the function for the given builtin in the target register.
    338   void GetBuiltinFunction(Register target, int native_context_index);
    339 
    340   // Expression support
    341   // cvtsi2sd instruction only writes to the low 64-bit of dst register, which
    342   // hinders register renaming and makes dependence chains longer. So we use
    343   // xorps to clear the dst register before cvtsi2sd to solve this issue.
    344   void Cvtsi2sd(XMMRegister dst, Register src) { Cvtsi2sd(dst, Operand(src)); }
    345   void Cvtsi2sd(XMMRegister dst, const Operand& src);
    346 
    347   // Support for constant splitting.
    348   bool IsUnsafeImmediate(const Immediate& x);
    349   void SafeMove(Register dst, const Immediate& x);
    350   void SafePush(const Immediate& x);
    351 
    352   // Compare object type for heap object.
    353   // Incoming register is heap_object and outgoing register is map.
    354   void CmpObjectType(Register heap_object, InstanceType type, Register map);
    355 
    356   // Compare instance type for map.
    357   void CmpInstanceType(Register map, InstanceType type);
    358 
    359   // Check if a map for a JSObject indicates that the object has fast elements.
    360   // Jump to the specified label if it does not.
    361   void CheckFastElements(Register map, Label* fail,
    362                          Label::Distance distance = Label::kFar);
    363 
    364   // Check if a map for a JSObject indicates that the object can have both smi
    365   // and HeapObject elements.  Jump to the specified label if it does not.
    366   void CheckFastObjectElements(Register map, Label* fail,
    367                                Label::Distance distance = Label::kFar);
    368 
    369   // Check if a map for a JSObject indicates that the object has fast smi only
    370   // elements.  Jump to the specified label if it does not.
    371   void CheckFastSmiElements(Register map, Label* fail,
    372                             Label::Distance distance = Label::kFar);
    373 
    374   // Check to see if maybe_number can be stored as a double in
    375   // FastDoubleElements. If it can, store it at the index specified by key in
    376   // the FastDoubleElements array elements, otherwise jump to fail.
    377   void StoreNumberToDoubleElements(Register maybe_number, Register elements,
    378                                    Register key, Register scratch1,
    379                                    XMMRegister scratch2, Label* fail,
    380                                    int offset = 0);
    381 
    382   // Compare an object's map with the specified map.
    383   void CompareMap(Register obj, Handle<Map> map);
    384 
    385   // Check if the map of an object is equal to a specified map and branch to
    386   // label if not. Skip the smi check if not required (object is known to be a
    387   // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
    388   // against maps that are ElementsKind transition maps of the specified map.
    389   void CheckMap(Register obj, Handle<Map> map, Label* fail,
    390                 SmiCheckType smi_check_type);
    391 
    392   // Check if the map of an object is equal to a specified weak map and branch
    393   // to a specified target if equal. Skip the smi check if not required
    394   // (object is known to be a heap object)
    395   void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
    396                        Handle<WeakCell> cell, Handle<Code> success,
    397                        SmiCheckType smi_check_type);
    398 
    399   // Check if the object in register heap_object is a string. Afterwards the
    400   // register map contains the object map and the register instance_type
    401   // contains the instance_type. The registers map and instance_type can be the
    402   // same in which case it contains the instance type afterwards. Either of the
    403   // registers map and instance_type can be the same as heap_object.
    404   Condition IsObjectStringType(Register heap_object, Register map,
    405                                Register instance_type);
    406 
    407   // Check if the object in register heap_object is a name. Afterwards the
    408   // register map contains the object map and the register instance_type
    409   // contains the instance_type. The registers map and instance_type can be the
    410   // same in which case it contains the instance type afterwards. Either of the
    411   // registers map and instance_type can be the same as heap_object.
    412   Condition IsObjectNameType(Register heap_object, Register map,
    413                              Register instance_type);
    414 
    415   // FCmp is similar to integer cmp, but requires unsigned
    416   // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
    417   void FCmp();
    418 
    419   void ClampUint8(Register reg);
    420 
    421   void ClampDoubleToUint8(XMMRegister input_reg, XMMRegister scratch_reg,
    422                           Register result_reg);
    423 
    424   void SlowTruncateToI(Register result_reg, Register input_reg,
    425       int offset = HeapNumber::kValueOffset - kHeapObjectTag);
    426 
    427   void TruncateHeapNumberToI(Register result_reg, Register input_reg);
    428   void TruncateDoubleToI(Register result_reg, XMMRegister input_reg);
    429 
    430   void DoubleToI(Register result_reg, XMMRegister input_reg,
    431                  XMMRegister scratch, MinusZeroMode minus_zero_mode,
    432                  Label* lost_precision, Label* is_nan, Label* minus_zero,
    433                  Label::Distance dst = Label::kFar);
    434 
    435   // Smi tagging support.
    436   void SmiTag(Register reg) {
    437     STATIC_ASSERT(kSmiTag == 0);
    438     STATIC_ASSERT(kSmiTagSize == 1);
    439     add(reg, reg);
    440   }
    441   void SmiUntag(Register reg) {
    442     sar(reg, kSmiTagSize);
    443   }
    444 
    445   // Modifies the register even if it does not contain a Smi!
    446   void SmiUntag(Register reg, Label* is_smi) {
    447     STATIC_ASSERT(kSmiTagSize == 1);
    448     sar(reg, kSmiTagSize);
    449     STATIC_ASSERT(kSmiTag == 0);
    450     j(not_carry, is_smi);
    451   }
    452 
    453   void LoadUint32(XMMRegister dst, Register src) {
    454     LoadUint32(dst, Operand(src));
    455   }
    456   void LoadUint32(XMMRegister dst, const Operand& src);
    457 
    458   // Jump the register contains a smi.
    459   inline void JumpIfSmi(Register value, Label* smi_label,
    460                         Label::Distance distance = Label::kFar) {
    461     test(value, Immediate(kSmiTagMask));
    462     j(zero, smi_label, distance);
    463   }
    464   // Jump if the operand is a smi.
    465   inline void JumpIfSmi(Operand value, Label* smi_label,
    466                         Label::Distance distance = Label::kFar) {
    467     test(value, Immediate(kSmiTagMask));
    468     j(zero, smi_label, distance);
    469   }
    470   // Jump if register contain a non-smi.
    471   inline void JumpIfNotSmi(Register value, Label* not_smi_label,
    472                            Label::Distance distance = Label::kFar) {
    473     test(value, Immediate(kSmiTagMask));
    474     j(not_zero, not_smi_label, distance);
    475   }
    476 
    477   void LoadInstanceDescriptors(Register map, Register descriptors);
    478   void EnumLength(Register dst, Register map);
    479   void NumberOfOwnDescriptors(Register dst, Register map);
    480   void LoadAccessor(Register dst, Register holder, int accessor_index,
    481                     AccessorComponent accessor);
    482 
    483   template<typename Field>
    484   void DecodeField(Register reg) {
    485     static const int shift = Field::kShift;
    486     static const int mask = Field::kMask >> Field::kShift;
    487     if (shift != 0) {
    488       sar(reg, shift);
    489     }
    490     and_(reg, Immediate(mask));
    491   }
    492 
    493   template<typename Field>
    494   void DecodeFieldToSmi(Register reg) {
    495     static const int shift = Field::kShift;
    496     static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize;
    497     STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0);
    498     STATIC_ASSERT(kSmiTag == 0);
    499     if (shift < kSmiTagSize) {
    500       shl(reg, kSmiTagSize - shift);
    501     } else if (shift > kSmiTagSize) {
    502       sar(reg, shift - kSmiTagSize);
    503     }
    504     and_(reg, Immediate(mask));
    505   }
    506 
    507   void LoadPowerOf2(XMMRegister dst, Register scratch, int power);
    508 
    509   // Abort execution if argument is not a number, enabled via --debug-code.
    510   void AssertNumber(Register object);
    511 
    512   // Abort execution if argument is not a smi, enabled via --debug-code.
    513   void AssertSmi(Register object);
    514 
    515   // Abort execution if argument is a smi, enabled via --debug-code.
    516   void AssertNotSmi(Register object);
    517 
    518   // Abort execution if argument is not a string, enabled via --debug-code.
    519   void AssertString(Register object);
    520 
    521   // Abort execution if argument is not a name, enabled via --debug-code.
    522   void AssertName(Register object);
    523 
    524   // Abort execution if argument is not a JSFunction, enabled via --debug-code.
    525   void AssertFunction(Register object);
    526 
    527   // Abort execution if argument is not a JSBoundFunction,
    528   // enabled via --debug-code.
    529   void AssertBoundFunction(Register object);
    530 
    531   // Abort execution if argument is not undefined or an AllocationSite, enabled
    532   // via --debug-code.
    533   void AssertUndefinedOrAllocationSite(Register object);
    534 
    535   // ---------------------------------------------------------------------------
    536   // Exception handling
    537 
    538   // Push a new stack handler and link it into stack handler chain.
    539   void PushStackHandler();
    540 
    541   // Unlink the stack handler on top of the stack from the stack handler chain.
    542   void PopStackHandler();
    543 
    544   // ---------------------------------------------------------------------------
    545   // Inline caching support
    546 
    547   // Generate code for checking access rights - used for security checks
    548   // on access to global objects across environments. The holder register
    549   // is left untouched, but the scratch register is clobbered.
    550   void CheckAccessGlobalProxy(Register holder_reg, Register scratch1,
    551                               Register scratch2, Label* miss);
    552 
    553   void GetNumberHash(Register r0, Register scratch);
    554 
    555   void LoadFromNumberDictionary(Label* miss, Register elements, Register key,
    556                                 Register r0, Register r1, Register r2,
    557                                 Register result);
    558 
    559   // ---------------------------------------------------------------------------
    560   // Allocation support
    561 
    562   // Allocate an object in new space or old space. If the given space
    563   // is exhausted control continues at the gc_required label. The allocated
    564   // object is returned in result and end of the new object is returned in
    565   // result_end. The register scratch can be passed as no_reg in which case
    566   // an additional object reference will be added to the reloc info. The
    567   // returned pointers in result and result_end have not yet been tagged as
    568   // heap objects. If result_contains_top_on_entry is true the content of
    569   // result is known to be the allocation top on entry (could be result_end
    570   // from a previous call). If result_contains_top_on_entry is true scratch
    571   // should be no_reg as it is never used.
    572   void Allocate(int object_size, Register result, Register result_end,
    573                 Register scratch, Label* gc_required, AllocationFlags flags);
    574 
    575   void Allocate(int header_size, ScaleFactor element_size,
    576                 Register element_count, RegisterValueType element_count_type,
    577                 Register result, Register result_end, Register scratch,
    578                 Label* gc_required, AllocationFlags flags);
    579 
    580   void Allocate(Register object_size, Register result, Register result_end,
    581                 Register scratch, Label* gc_required, AllocationFlags flags);
    582 
    583   // Allocate a heap number in new space with undefined value. The
    584   // register scratch2 can be passed as no_reg; the others must be
    585   // valid registers. Returns tagged pointer in result register, or
    586   // jumps to gc_required if new space is full.
    587   void AllocateHeapNumber(Register result, Register scratch1, Register scratch2,
    588                           Label* gc_required, MutableMode mode = IMMUTABLE);
    589 
    590   // Allocate a sequential string. All the header fields of the string object
    591   // are initialized.
    592   void AllocateTwoByteString(Register result, Register length,
    593                              Register scratch1, Register scratch2,
    594                              Register scratch3, Label* gc_required);
    595   void AllocateOneByteString(Register result, Register length,
    596                              Register scratch1, Register scratch2,
    597                              Register scratch3, Label* gc_required);
    598   void AllocateOneByteString(Register result, int length, Register scratch1,
    599                              Register scratch2, Label* gc_required);
    600 
    601   // Allocate a raw cons string object. Only the map field of the result is
    602   // initialized.
    603   void AllocateTwoByteConsString(Register result, Register scratch1,
    604                                  Register scratch2, Label* gc_required);
    605   void AllocateOneByteConsString(Register result, Register scratch1,
    606                                  Register scratch2, 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, Register scratch1,
    611                                    Register scratch2, Label* gc_required);
    612   void AllocateOneByteSlicedString(Register result, Register scratch1,
    613                                    Register scratch2, Label* gc_required);
    614 
    615   // Allocate and initialize a JSValue wrapper with the specified {constructor}
    616   // and {value}.
    617   void AllocateJSValue(Register result, Register constructor, Register value,
    618                        Register scratch, Label* gc_required);
    619 
    620   // Copy memory, byte-by-byte, from source to destination.  Not optimized for
    621   // long or aligned copies.
    622   // The contents of index and scratch are destroyed.
    623   void CopyBytes(Register source, Register destination, Register length,
    624                  Register scratch);
    625 
    626   // Initialize fields with filler values.  Fields starting at |current_address|
    627   // not including |end_address| are overwritten with the value in |filler|.  At
    628   // the end the loop, |current_address| takes the value of |end_address|.
    629   void InitializeFieldsWithFiller(Register current_address,
    630                                   Register end_address, Register filler);
    631 
    632   // ---------------------------------------------------------------------------
    633   // Support functions.
    634 
    635   // Check a boolean-bit of a Smi field.
    636   void BooleanBitTest(Register object, int field_offset, int bit_index);
    637 
    638   // Check if result is zero and op is negative.
    639   void NegativeZeroTest(Register result, Register op, Label* then_label);
    640 
    641   // Check if result is zero and any of op1 and op2 are negative.
    642   // Register scratch is destroyed, and it must be different from op2.
    643   void NegativeZeroTest(Register result, Register op1, Register op2,
    644                         Register scratch, Label* then_label);
    645 
    646   // Machine code version of Map::GetConstructor().
    647   // |temp| holds |result|'s map when done.
    648   void GetMapConstructor(Register result, Register map, Register temp);
    649 
    650   // Try to get function prototype of a function and puts the value in
    651   // the result register. Checks that the function really is a
    652   // function and jumps to the miss label if the fast checks fail. The
    653   // function register will be untouched; the other registers may be
    654   // clobbered.
    655   void TryGetFunctionPrototype(Register function, Register result,
    656                                Register scratch, Label* miss);
    657 
    658   // Picks out an array index from the hash field.
    659   // Register use:
    660   //   hash - holds the index's hash. Clobbered.
    661   //   index - holds the overwritten index on exit.
    662   void IndexFromHash(Register hash, Register index);
    663 
    664   // ---------------------------------------------------------------------------
    665   // Runtime calls
    666 
    667   // Call a code stub.  Generate the code if necessary.
    668   void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
    669 
    670   // Tail call a code stub (jump).  Generate the code if necessary.
    671   void TailCallStub(CodeStub* stub);
    672 
    673   // Return from a code stub after popping its arguments.
    674   void StubReturn(int argc);
    675 
    676   // Call a runtime routine.
    677   void CallRuntime(const Runtime::Function* f, int num_arguments,
    678                    SaveFPRegsMode save_doubles = kDontSaveFPRegs);
    679   void CallRuntimeSaveDoubles(Runtime::FunctionId fid) {
    680     const Runtime::Function* function = Runtime::FunctionForId(fid);
    681     CallRuntime(function, function->nargs, kSaveFPRegs);
    682   }
    683 
    684   // Convenience function: Same as above, but takes the fid instead.
    685   void CallRuntime(Runtime::FunctionId fid,
    686                    SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
    687     const Runtime::Function* function = Runtime::FunctionForId(fid);
    688     CallRuntime(function, function->nargs, save_doubles);
    689   }
    690 
    691   // Convenience function: Same as above, but takes the fid instead.
    692   void CallRuntime(Runtime::FunctionId fid, int num_arguments,
    693                    SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
    694     CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
    695   }
    696 
    697   // Convenience function: call an external reference.
    698   void CallExternalReference(ExternalReference ref, int num_arguments);
    699 
    700   // Convenience function: tail call a runtime routine (jump).
    701   void TailCallRuntime(Runtime::FunctionId fid);
    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   // Jump to a runtime routine.
    721   void JumpToExternalReference(const ExternalReference& ext);
    722 
    723   // ---------------------------------------------------------------------------
    724   // Utilities
    725 
    726   void Ret();
    727 
    728   // Return and drop arguments from stack, where the number of arguments
    729   // may be bigger than 2^16 - 1.  Requires a scratch register.
    730   void Ret(int bytes_dropped, Register scratch);
    731 
    732   // Emit code to discard a non-negative number of pointer-sized elements
    733   // from the stack, clobbering only the esp register.
    734   void Drop(int element_count);
    735 
    736   void Call(Label* target) { call(target); }
    737   void Call(Handle<Code> target, RelocInfo::Mode rmode) { call(target, rmode); }
    738   void Jump(Handle<Code> target, RelocInfo::Mode rmode) { jmp(target, rmode); }
    739   void Push(Register src) { push(src); }
    740   void Push(const Operand& src) { push(src); }
    741   void Push(Immediate value) { push(value); }
    742   void Pop(Register dst) { pop(dst); }
    743   void Pop(const Operand& dst) { pop(dst); }
    744   void PushReturnAddressFrom(Register src) { push(src); }
    745   void PopReturnAddressTo(Register dst) { pop(dst); }
    746 
    747   // Non-SSE2 instructions.
    748   void Pextrd(Register dst, XMMRegister src, int8_t imm8);
    749   void Pinsrd(XMMRegister dst, Register src, int8_t imm8) {
    750     Pinsrd(dst, Operand(src), imm8);
    751   }
    752   void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
    753 
    754   void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); }
    755   void Lzcnt(Register dst, const Operand& src);
    756 
    757   void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); }
    758   void Tzcnt(Register dst, const Operand& src);
    759 
    760   void Popcnt(Register dst, Register src) { Popcnt(dst, Operand(src)); }
    761   void Popcnt(Register dst, const Operand& src);
    762 
    763   // Emit call to the code we are currently generating.
    764   void CallSelf() {
    765     Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
    766     call(self, RelocInfo::CODE_TARGET);
    767   }
    768 
    769   // Move if the registers are not identical.
    770   void Move(Register target, Register source);
    771 
    772   // Move a constant into a destination using the most efficient encoding.
    773   void Move(Register dst, const Immediate& x);
    774   void Move(const Operand& dst, const Immediate& x);
    775 
    776   // Move an immediate into an XMM register.
    777   void Move(XMMRegister dst, uint32_t src);
    778   void Move(XMMRegister dst, uint64_t src);
    779   void Move(XMMRegister dst, double src) { Move(dst, bit_cast<uint64_t>(src)); }
    780 
    781   void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); }
    782 
    783   // Push a handle value.
    784   void Push(Handle<Object> handle) { push(Immediate(handle)); }
    785   void Push(Smi* smi) { Push(Immediate(smi)); }
    786 
    787   Handle<Object> CodeObject() {
    788     DCHECK(!code_object_.is_null());
    789     return code_object_;
    790   }
    791 
    792   // Emit code for a truncating division by a constant. The dividend register is
    793   // unchanged, the result is in edx, and eax gets clobbered.
    794   void TruncatingDiv(Register dividend, int32_t divisor);
    795 
    796   // ---------------------------------------------------------------------------
    797   // StatsCounter support
    798 
    799   void SetCounter(StatsCounter* counter, int value);
    800   void IncrementCounter(StatsCounter* counter, int value);
    801   void DecrementCounter(StatsCounter* counter, int value);
    802   void IncrementCounter(Condition cc, StatsCounter* counter, int value);
    803   void DecrementCounter(Condition cc, StatsCounter* counter, int value);
    804 
    805   // ---------------------------------------------------------------------------
    806   // Debugging
    807 
    808   // Calls Abort(msg) if the condition cc is not satisfied.
    809   // Use --debug_code to enable.
    810   void Assert(Condition cc, BailoutReason reason);
    811 
    812   void AssertFastElements(Register elements);
    813 
    814   // Like Assert(), but always enabled.
    815   void Check(Condition cc, BailoutReason reason);
    816 
    817   // Print a message to stdout and abort execution.
    818   void Abort(BailoutReason reason);
    819 
    820   // Check that the stack is aligned.
    821   void CheckStackAlignment();
    822 
    823   // Verify restrictions about code generated in stubs.
    824   void set_generating_stub(bool value) { generating_stub_ = value; }
    825   bool generating_stub() { return generating_stub_; }
    826   void set_has_frame(bool value) { has_frame_ = value; }
    827   bool has_frame() { return has_frame_; }
    828   inline bool AllowThisStubCall(CodeStub* stub);
    829 
    830   // ---------------------------------------------------------------------------
    831   // String utilities.
    832 
    833   // Check whether the instance type represents a flat one-byte string. Jump to
    834   // the label if not. If the instance type can be scratched specify same
    835   // register for both instance type and scratch.
    836   void JumpIfInstanceTypeIsNotSequentialOneByte(
    837       Register instance_type, Register scratch,
    838       Label* on_not_flat_one_byte_string);
    839 
    840   // Checks if both objects are sequential one-byte strings, and jumps to label
    841   // if either is not.
    842   void JumpIfNotBothSequentialOneByteStrings(
    843       Register object1, Register object2, Register scratch1, Register scratch2,
    844       Label* on_not_flat_one_byte_strings);
    845 
    846   // Checks if the given register or operand is a unique name
    847   void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name,
    848                                        Label::Distance distance = Label::kFar) {
    849     JumpIfNotUniqueNameInstanceType(Operand(reg), not_unique_name, distance);
    850   }
    851 
    852   void JumpIfNotUniqueNameInstanceType(Operand operand, Label* not_unique_name,
    853                                        Label::Distance distance = Label::kFar);
    854 
    855   void EmitSeqStringSetCharCheck(Register string, Register index,
    856                                  Register value, uint32_t encoding_mask);
    857 
    858   static int SafepointRegisterStackIndex(Register reg) {
    859     return SafepointRegisterStackIndex(reg.code());
    860   }
    861 
    862   // Load the type feedback vector from a JavaScript frame.
    863   void EmitLoadTypeFeedbackVector(Register vector);
    864 
    865   // Activation support.
    866   void EnterFrame(StackFrame::Type type);
    867   void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
    868   void LeaveFrame(StackFrame::Type type);
    869 
    870   // Expects object in eax and returns map with validated enum cache
    871   // in eax.  Assumes that any other register can be used as a scratch.
    872   void CheckEnumCache(Label* call_runtime);
    873 
    874   // AllocationMemento support. Arrays may have an associated
    875   // AllocationMemento object that can be checked for in order to pretransition
    876   // to another type.
    877   // On entry, receiver_reg should point to the array object.
    878   // scratch_reg gets clobbered.
    879   // If allocation info is present, conditional code is set to equal.
    880   void TestJSArrayForAllocationMemento(Register receiver_reg,
    881                                        Register scratch_reg,
    882                                        Label* no_memento_found);
    883 
    884   void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
    885                                          Register scratch_reg,
    886                                          Label* memento_found) {
    887     Label no_memento_found;
    888     TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
    889                                     &no_memento_found);
    890     j(equal, memento_found);
    891     bind(&no_memento_found);
    892   }
    893 
    894   // Jumps to found label if a prototype map has dictionary elements.
    895   void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
    896                                         Register scratch1, Label* found);
    897 
    898  private:
    899   bool generating_stub_;
    900   bool has_frame_;
    901   // This handle will be patched with the code object on installation.
    902   Handle<Object> code_object_;
    903 
    904   // Helper functions for generating invokes.
    905   void InvokePrologue(const ParameterCount& expected,
    906                       const ParameterCount& actual, Label* done,
    907                       bool* definitely_mismatches, InvokeFlag flag,
    908                       Label::Distance done_distance,
    909                       const CallWrapper& call_wrapper);
    910 
    911   void EnterExitFramePrologue();
    912   void EnterExitFrameEpilogue(int argc, bool save_doubles);
    913 
    914   void LeaveExitFrameEpilogue(bool restore_context);
    915 
    916   // Allocation support helpers.
    917   void LoadAllocationTopHelper(Register result, Register scratch,
    918                                AllocationFlags flags);
    919 
    920   void UpdateAllocationTopHelper(Register result_end, Register scratch,
    921                                  AllocationFlags flags);
    922 
    923   // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
    924   void InNewSpace(Register object, Register scratch, Condition cc,
    925                   Label* condition_met,
    926                   Label::Distance condition_met_distance = Label::kFar);
    927 
    928   // Helper for finding the mark bits for an address.  Afterwards, the
    929   // bitmap register points at the word with the mark bits and the mask
    930   // the position of the first bit.  Uses ecx as scratch and leaves addr_reg
    931   // unchanged.
    932   inline void GetMarkBits(Register addr_reg, Register bitmap_reg,
    933                           Register mask_reg);
    934 
    935   // Compute memory operands for safepoint stack slots.
    936   Operand SafepointRegisterSlot(Register reg);
    937   static int SafepointRegisterStackIndex(int reg_code);
    938 
    939   // Needs access to SafepointRegisterStackIndex for compiled frame
    940   // traversal.
    941   friend class StandardFrame;
    942 };
    943 
    944 // The code patcher is used to patch (typically) small parts of code e.g. for
    945 // debugging and other types of instrumentation. When using the code patcher
    946 // the exact number of bytes specified must be emitted. Is not legal to emit
    947 // relocation information. If any of these constraints are violated it causes
    948 // an assertion.
    949 class CodePatcher {
    950  public:
    951   CodePatcher(Isolate* isolate, byte* address, int size);
    952   ~CodePatcher();
    953 
    954   // Macro assembler to emit code.
    955   MacroAssembler* masm() { return &masm_; }
    956 
    957  private:
    958   byte* address_;        // The address of the code being patched.
    959   int size_;             // Number of bytes of the expected patch size.
    960   MacroAssembler masm_;  // Macro assembler used to generate the code.
    961 };
    962 
    963 // -----------------------------------------------------------------------------
    964 // Static helper functions.
    965 
    966 // Generate an Operand for loading a field from an object.
    967 inline Operand FieldOperand(Register object, int offset) {
    968   return Operand(object, offset - kHeapObjectTag);
    969 }
    970 
    971 // Generate an Operand for loading an indexed field from an object.
    972 inline Operand FieldOperand(Register object, Register index, ScaleFactor scale,
    973                             int offset) {
    974   return Operand(object, index, scale, offset - kHeapObjectTag);
    975 }
    976 
    977 inline Operand FixedArrayElementOperand(Register array, Register index_as_smi,
    978                                         int additional_offset = 0) {
    979   int offset = FixedArray::kHeaderSize + additional_offset * kPointerSize;
    980   return FieldOperand(array, index_as_smi, times_half_pointer_size, offset);
    981 }
    982 
    983 inline Operand ContextOperand(Register context, int index) {
    984   return Operand(context, Context::SlotOffset(index));
    985 }
    986 
    987 inline Operand ContextOperand(Register context, Register index) {
    988   return Operand(context, index, times_pointer_size, Context::SlotOffset(0));
    989 }
    990 
    991 inline Operand NativeContextOperand() {
    992   return ContextOperand(esi, Context::NATIVE_CONTEXT_INDEX);
    993 }
    994 
    995 #ifdef GENERATED_CODE_COVERAGE
    996 extern void LogGeneratedCodeCoverage(const char* file_line);
    997 #define CODE_COVERAGE_STRINGIFY(x) #x
    998 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
    999 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
   1000 #define ACCESS_MASM(masm) {                                               \
   1001     byte* ia32_coverage_function =                                        \
   1002         reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
   1003     masm->pushfd();                                                       \
   1004     masm->pushad();                                                       \
   1005     masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__)));         \
   1006     masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY);         \
   1007     masm->pop(eax);                                                       \
   1008     masm->popad();                                                        \
   1009     masm->popfd();                                                        \
   1010   }                                                                       \
   1011   masm->
   1012 #else
   1013 #define ACCESS_MASM(masm) masm->
   1014 #endif
   1015 
   1016 }  // namespace internal
   1017 }  // namespace v8
   1018 
   1019 #endif  // V8_IA32_MACRO_ASSEMBLER_IA32_H_
   1020