Home | History | Annotate | Download | only in x87
      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_X87_MACRO_ASSEMBLER_X87_H_
      6 #define V8_X87_MACRO_ASSEMBLER_X87_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   void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
    296   void GetWeakValue(Register value, Handle<WeakCell> cell);
    297   void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
    298 
    299   // ---------------------------------------------------------------------------
    300   // JavaScript invokes
    301 
    302   // Invoke the JavaScript function code by either calling or jumping.
    303 
    304   void InvokeFunctionCode(Register function, Register new_target,
    305                           const ParameterCount& expected,
    306                           const ParameterCount& actual, InvokeFlag flag,
    307                           const CallWrapper& call_wrapper);
    308 
    309   void FloodFunctionIfStepping(Register fun, Register new_target,
    310                                const ParameterCount& expected,
    311                                const ParameterCount& actual);
    312 
    313   // Invoke the JavaScript function in the given register. Changes the
    314   // current context to the context in the function before invoking.
    315   void InvokeFunction(Register function, Register new_target,
    316                       const ParameterCount& actual, InvokeFlag flag,
    317                       const CallWrapper& call_wrapper);
    318 
    319   void InvokeFunction(Register function, const ParameterCount& expected,
    320                       const ParameterCount& actual, InvokeFlag flag,
    321                       const CallWrapper& call_wrapper);
    322 
    323   void InvokeFunction(Handle<JSFunction> function,
    324                       const ParameterCount& expected,
    325                       const ParameterCount& actual, InvokeFlag flag,
    326                       const CallWrapper& call_wrapper);
    327 
    328   // Invoke specified builtin JavaScript function.
    329   void InvokeBuiltin(int native_context_index, InvokeFlag flag,
    330                      const CallWrapper& call_wrapper = NullCallWrapper());
    331 
    332   // Store the function for the given builtin in the target register.
    333   void GetBuiltinFunction(Register target, int native_context_index);
    334 
    335 
    336   // Expression support
    337   // Support for constant splitting.
    338   bool IsUnsafeImmediate(const Immediate& x);
    339   void SafeMove(Register dst, const Immediate& x);
    340   void SafePush(const Immediate& x);
    341 
    342   // Compare object type for heap object.
    343   // Incoming register is heap_object and outgoing register is map.
    344   void CmpObjectType(Register heap_object, InstanceType type, Register map);
    345 
    346   // Compare instance type for map.
    347   void CmpInstanceType(Register map, InstanceType type);
    348 
    349   // Check if a map for a JSObject indicates that the object has fast elements.
    350   // Jump to the specified label if it does not.
    351   void CheckFastElements(Register map, Label* fail,
    352                          Label::Distance distance = Label::kFar);
    353 
    354   // Check if a map for a JSObject indicates that the object can have both smi
    355   // and HeapObject elements.  Jump to the specified label if it does not.
    356   void CheckFastObjectElements(Register map, Label* fail,
    357                                Label::Distance distance = Label::kFar);
    358 
    359   // Check if a map for a JSObject indicates that the object has fast smi only
    360   // elements.  Jump to the specified label if it does not.
    361   void CheckFastSmiElements(Register map, 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, Register elements,
    368                                    Register key, Register scratch, Label* fail,
    369                                    int offset = 0);
    370 
    371   // Compare an object's map with the specified map.
    372   void CompareMap(Register obj, Handle<Map> map);
    373 
    374   // Check if the map of an object is equal to a specified map and branch to
    375   // label if not. Skip the smi check if not required (object is known to be a
    376   // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
    377   // against maps that are ElementsKind transition maps of the specified map.
    378   void CheckMap(Register obj, Handle<Map> map, Label* fail,
    379                 SmiCheckType smi_check_type);
    380 
    381   // Check if the map of an object is equal to a specified weak map and branch
    382   // to a specified target if equal. Skip the smi check if not required
    383   // (object is known to be a heap object)
    384   void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
    385                        Handle<WeakCell> cell, Handle<Code> success,
    386                        SmiCheckType smi_check_type);
    387 
    388   // Check if the object in register heap_object is a string. Afterwards the
    389   // register map contains the object map and the register instance_type
    390   // contains the instance_type. The registers map and instance_type can be the
    391   // same in which case it contains the instance type afterwards. Either of the
    392   // registers map and instance_type can be the same as heap_object.
    393   Condition IsObjectStringType(Register heap_object, Register map,
    394                                Register instance_type);
    395 
    396   // Check if the object in register heap_object is a name. Afterwards the
    397   // register map contains the object map and the register instance_type
    398   // contains the instance_type. The registers map and instance_type can be the
    399   // same in which case it contains the instance type afterwards. Either of the
    400   // registers map and instance_type can be the same as heap_object.
    401   Condition IsObjectNameType(Register heap_object, Register map,
    402                              Register instance_type);
    403 
    404   // FCmp is similar to integer cmp, but requires unsigned
    405   // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
    406   void FCmp();
    407   void FXamMinusZero();
    408   void FXamSign();
    409   void X87CheckIA();
    410   void X87SetRC(int rc);
    411   void X87SetFPUCW(int cw);
    412 
    413   void ClampUint8(Register reg);
    414   void ClampTOSToUint8(Register result_reg);
    415 
    416   void SlowTruncateToI(Register result_reg, Register input_reg,
    417       int offset = HeapNumber::kValueOffset - kHeapObjectTag);
    418 
    419   void TruncateHeapNumberToI(Register result_reg, Register input_reg);
    420   void TruncateX87TOSToI(Register result_reg);
    421 
    422   void X87TOSToI(Register result_reg, MinusZeroMode minus_zero_mode,
    423       Label* lost_precision, Label* is_nan, Label* minus_zero,
    424       Label::Distance dst = Label::kFar);
    425 
    426   // Smi tagging support.
    427   void SmiTag(Register reg) {
    428     STATIC_ASSERT(kSmiTag == 0);
    429     STATIC_ASSERT(kSmiTagSize == 1);
    430     add(reg, reg);
    431   }
    432   void SmiUntag(Register reg) {
    433     sar(reg, kSmiTagSize);
    434   }
    435 
    436   // Modifies the register even if it does not contain a Smi!
    437   void SmiUntag(Register reg, Label* is_smi) {
    438     STATIC_ASSERT(kSmiTagSize == 1);
    439     sar(reg, kSmiTagSize);
    440     STATIC_ASSERT(kSmiTag == 0);
    441     j(not_carry, is_smi);
    442   }
    443 
    444   void LoadUint32NoSSE2(Register src) {
    445     LoadUint32NoSSE2(Operand(src));
    446   }
    447   void LoadUint32NoSSE2(const Operand& src);
    448 
    449   // Jump the register contains a smi.
    450   inline void JumpIfSmi(Register value, Label* smi_label,
    451                         Label::Distance distance = Label::kFar) {
    452     test(value, Immediate(kSmiTagMask));
    453     j(zero, smi_label, distance);
    454   }
    455   // Jump if the operand is a smi.
    456   inline void JumpIfSmi(Operand value, Label* smi_label,
    457                         Label::Distance distance = Label::kFar) {
    458     test(value, Immediate(kSmiTagMask));
    459     j(zero, smi_label, distance);
    460   }
    461   // Jump if register contain a non-smi.
    462   inline void JumpIfNotSmi(Register value, Label* not_smi_label,
    463                            Label::Distance distance = Label::kFar) {
    464     test(value, Immediate(kSmiTagMask));
    465     j(not_zero, not_smi_label, distance);
    466   }
    467 
    468   void LoadInstanceDescriptors(Register map, Register descriptors);
    469   void EnumLength(Register dst, Register map);
    470   void NumberOfOwnDescriptors(Register dst, Register map);
    471   void LoadAccessor(Register dst, Register holder, int accessor_index,
    472                     AccessorComponent accessor);
    473 
    474   template<typename Field>
    475   void DecodeField(Register reg) {
    476     static const int shift = Field::kShift;
    477     static const int mask = Field::kMask >> Field::kShift;
    478     if (shift != 0) {
    479       sar(reg, shift);
    480     }
    481     and_(reg, Immediate(mask));
    482   }
    483 
    484   template<typename Field>
    485   void DecodeFieldToSmi(Register reg) {
    486     static const int shift = Field::kShift;
    487     static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize;
    488     STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0);
    489     STATIC_ASSERT(kSmiTag == 0);
    490     if (shift < kSmiTagSize) {
    491       shl(reg, kSmiTagSize - shift);
    492     } else if (shift > kSmiTagSize) {
    493       sar(reg, shift - kSmiTagSize);
    494     }
    495     and_(reg, Immediate(mask));
    496   }
    497 
    498   // Abort execution if argument is not a number, enabled via --debug-code.
    499   void AssertNumber(Register object);
    500 
    501   // Abort execution if argument is not a smi, enabled via --debug-code.
    502   void AssertSmi(Register object);
    503 
    504   // Abort execution if argument is a smi, enabled via --debug-code.
    505   void AssertNotSmi(Register object);
    506 
    507   // Abort execution if argument is not a string, enabled via --debug-code.
    508   void AssertString(Register object);
    509 
    510   // Abort execution if argument is not a name, enabled via --debug-code.
    511   void AssertName(Register object);
    512 
    513   // Abort execution if argument is not a JSFunction, enabled via --debug-code.
    514   void AssertFunction(Register object);
    515 
    516   // Abort execution if argument is not a JSBoundFunction,
    517   // enabled via --debug-code.
    518   void AssertBoundFunction(Register object);
    519 
    520   // Abort execution if argument is not undefined or an AllocationSite, enabled
    521   // via --debug-code.
    522   void AssertUndefinedOrAllocationSite(Register object);
    523 
    524   // ---------------------------------------------------------------------------
    525   // Exception handling
    526 
    527   // Push a new stack handler and link it into stack handler chain.
    528   void PushStackHandler();
    529 
    530   // Unlink the stack handler on top of the stack from the stack handler chain.
    531   void PopStackHandler();
    532 
    533   // ---------------------------------------------------------------------------
    534   // Inline caching support
    535 
    536   // Generate code for checking access rights - used for security checks
    537   // on access to global objects across environments. The holder register
    538   // is left untouched, but the scratch register is clobbered.
    539   void CheckAccessGlobalProxy(Register holder_reg, Register scratch1,
    540                               Register scratch2, Label* miss);
    541 
    542   void GetNumberHash(Register r0, Register scratch);
    543 
    544   void LoadFromNumberDictionary(Label* miss, Register elements, Register key,
    545                                 Register r0, Register r1, Register r2,
    546                                 Register result);
    547 
    548   // ---------------------------------------------------------------------------
    549   // Allocation support
    550 
    551   // Allocate an object in new space or old space. If the given space
    552   // is exhausted control continues at the gc_required label. The allocated
    553   // object is returned in result and end of the new object is returned in
    554   // result_end. The register scratch can be passed as no_reg in which case
    555   // an additional object reference will be added to the reloc info. The
    556   // returned pointers in result and result_end have not yet been tagged as
    557   // heap objects. If result_contains_top_on_entry is true the content of
    558   // result is known to be the allocation top on entry (could be result_end
    559   // from a previous call). If result_contains_top_on_entry is true scratch
    560   // should be no_reg as it is never used.
    561   void Allocate(int object_size, Register result, Register result_end,
    562                 Register scratch, Label* gc_required, AllocationFlags flags);
    563 
    564   void Allocate(int header_size, ScaleFactor element_size,
    565                 Register element_count, RegisterValueType element_count_type,
    566                 Register result, Register result_end, Register scratch,
    567                 Label* gc_required, AllocationFlags flags);
    568 
    569   void Allocate(Register object_size, Register result, Register result_end,
    570                 Register scratch, Label* gc_required, AllocationFlags flags);
    571 
    572   // Allocate a heap number in new space with undefined value. The
    573   // register scratch2 can be passed as no_reg; the others must be
    574   // valid registers. Returns tagged pointer in result register, or
    575   // jumps to gc_required if new space is full.
    576   void AllocateHeapNumber(Register result, Register scratch1, Register scratch2,
    577                           Label* gc_required, MutableMode mode = IMMUTABLE);
    578 
    579   // Allocate a sequential string. All the header fields of the string object
    580   // are initialized.
    581   void AllocateTwoByteString(Register result, Register length,
    582                              Register scratch1, Register scratch2,
    583                              Register scratch3, Label* gc_required);
    584   void AllocateOneByteString(Register result, Register length,
    585                              Register scratch1, Register scratch2,
    586                              Register scratch3, Label* gc_required);
    587   void AllocateOneByteString(Register result, int length, Register scratch1,
    588                              Register scratch2, Label* gc_required);
    589 
    590   // Allocate a raw cons string object. Only the map field of the result is
    591   // initialized.
    592   void AllocateTwoByteConsString(Register result, Register scratch1,
    593                                  Register scratch2, Label* gc_required);
    594   void AllocateOneByteConsString(Register result, Register scratch1,
    595                                  Register scratch2, Label* gc_required);
    596 
    597   // Allocate a raw sliced string object. Only the map field of the result is
    598   // initialized.
    599   void AllocateTwoByteSlicedString(Register result, Register scratch1,
    600                                    Register scratch2, Label* gc_required);
    601   void AllocateOneByteSlicedString(Register result, Register scratch1,
    602                                    Register scratch2, Label* gc_required);
    603 
    604   // Allocate and initialize a JSValue wrapper with the specified {constructor}
    605   // and {value}.
    606   void AllocateJSValue(Register result, Register constructor, Register value,
    607                        Register scratch, Label* gc_required);
    608 
    609   // Copy memory, byte-by-byte, from source to destination.  Not optimized for
    610   // long or aligned copies.
    611   // The contents of index and scratch are destroyed.
    612   void CopyBytes(Register source, Register destination, Register length,
    613                  Register scratch);
    614 
    615   // Initialize fields with filler values.  Fields starting at |current_address|
    616   // not including |end_address| are overwritten with the value in |filler|.  At
    617   // the end the loop, |current_address| takes the value of |end_address|.
    618   void InitializeFieldsWithFiller(Register current_address,
    619                                   Register end_address, Register filler);
    620 
    621   // ---------------------------------------------------------------------------
    622   // Support functions.
    623 
    624   // Check a boolean-bit of a Smi field.
    625   void BooleanBitTest(Register object, int field_offset, int bit_index);
    626 
    627   // Check if result is zero and op is negative.
    628   void NegativeZeroTest(Register result, Register op, Label* then_label);
    629 
    630   // Check if result is zero and any of op1 and op2 are negative.
    631   // Register scratch is destroyed, and it must be different from op2.
    632   void NegativeZeroTest(Register result, Register op1, Register op2,
    633                         Register scratch, Label* then_label);
    634 
    635   // Machine code version of Map::GetConstructor().
    636   // |temp| holds |result|'s map when done.
    637   void GetMapConstructor(Register result, Register map, Register temp);
    638 
    639   // Try to get function prototype of a function and puts the value in
    640   // the result register. Checks that the function really is a
    641   // function and jumps to the miss label if the fast checks fail. The
    642   // function register will be untouched; the other registers may be
    643   // clobbered.
    644   void TryGetFunctionPrototype(Register function, Register result,
    645                                Register scratch, Label* miss);
    646 
    647   // Picks out an array index from the hash field.
    648   // Register use:
    649   //   hash - holds the index's hash. Clobbered.
    650   //   index - holds the overwritten index on exit.
    651   void IndexFromHash(Register hash, Register index);
    652 
    653   // ---------------------------------------------------------------------------
    654   // Runtime calls
    655 
    656   // Call a code stub.  Generate the code if necessary.
    657   void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
    658 
    659   // Tail call a code stub (jump).  Generate the code if necessary.
    660   void TailCallStub(CodeStub* stub);
    661 
    662   // Return from a code stub after popping its arguments.
    663   void StubReturn(int argc);
    664 
    665   // Call a runtime routine.
    666   void CallRuntime(const Runtime::Function* f, int num_arguments,
    667                    SaveFPRegsMode save_doubles = kDontSaveFPRegs);
    668   void CallRuntimeSaveDoubles(Runtime::FunctionId fid) {
    669     const Runtime::Function* function = Runtime::FunctionForId(fid);
    670     CallRuntime(function, function->nargs, kSaveFPRegs);
    671   }
    672 
    673   // Convenience function: Same as above, but takes the fid instead.
    674   void CallRuntime(Runtime::FunctionId fid,
    675                    SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
    676     const Runtime::Function* function = Runtime::FunctionForId(fid);
    677     CallRuntime(function, function->nargs, save_doubles);
    678   }
    679 
    680   // Convenience function: Same as above, but takes the fid instead.
    681   void CallRuntime(Runtime::FunctionId fid, int num_arguments,
    682                    SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
    683     CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
    684   }
    685 
    686   // Convenience function: call an external reference.
    687   void CallExternalReference(ExternalReference ref, int num_arguments);
    688 
    689   // Convenience function: tail call a runtime routine (jump).
    690   void TailCallRuntime(Runtime::FunctionId fid);
    691 
    692   // Before calling a C-function from generated code, align arguments on stack.
    693   // After aligning the frame, arguments must be stored in esp[0], esp[4],
    694   // etc., not pushed. The argument count assumes all arguments are word sized.
    695   // Some compilers/platforms require the stack to be aligned when calling
    696   // C++ code.
    697   // Needs a scratch register to do some arithmetic. This register will be
    698   // trashed.
    699   void PrepareCallCFunction(int num_arguments, Register scratch);
    700 
    701   // Calls a C function and cleans up the space for arguments allocated
    702   // by PrepareCallCFunction. The called function is not allowed to trigger a
    703   // garbage collection, since that might move the code and invalidate the
    704   // return address (unless this is somehow accounted for by the called
    705   // function).
    706   void CallCFunction(ExternalReference function, int num_arguments);
    707   void CallCFunction(Register function, int num_arguments);
    708 
    709   // Jump to a runtime routine.
    710   void JumpToExternalReference(const ExternalReference& ext);
    711 
    712   // ---------------------------------------------------------------------------
    713   // Utilities
    714 
    715   void Ret();
    716 
    717   // Return and drop arguments from stack, where the number of arguments
    718   // may be bigger than 2^16 - 1.  Requires a scratch register.
    719   void Ret(int bytes_dropped, Register scratch);
    720 
    721   // Emit code to discard a non-negative number of pointer-sized elements
    722   // from the stack, clobbering only the esp register.
    723   void Drop(int element_count);
    724 
    725   void Call(Label* target) { call(target); }
    726   void Call(Handle<Code> target, RelocInfo::Mode rmode) { call(target, rmode); }
    727   void Jump(Handle<Code> target, RelocInfo::Mode rmode) { jmp(target, rmode); }
    728   void Push(Register src) { push(src); }
    729   void Push(const Operand& src) { push(src); }
    730   void Push(Immediate value) { push(value); }
    731   void Pop(Register dst) { pop(dst); }
    732   void Pop(const Operand& dst) { pop(dst); }
    733   void PushReturnAddressFrom(Register src) { push(src); }
    734   void PopReturnAddressTo(Register dst) { pop(dst); }
    735 
    736   void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); }
    737   void Lzcnt(Register dst, const Operand& src);
    738 
    739   void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); }
    740   void Tzcnt(Register dst, const Operand& src);
    741 
    742   void Popcnt(Register dst, Register src) { Popcnt(dst, Operand(src)); }
    743   void Popcnt(Register dst, const Operand& src);
    744 
    745   // Emit call to the code we are currently generating.
    746   void CallSelf() {
    747     Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
    748     call(self, RelocInfo::CODE_TARGET);
    749   }
    750 
    751   // Move if the registers are not identical.
    752   void Move(Register target, Register source);
    753 
    754   // Move a constant into a destination using the most efficient encoding.
    755   void Move(Register dst, const Immediate& x);
    756   void Move(const Operand& dst, const Immediate& x);
    757 
    758   void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); }
    759 
    760   // Push a handle value.
    761   void Push(Handle<Object> handle) { push(Immediate(handle)); }
    762   void Push(Smi* smi) { Push(Immediate(smi)); }
    763 
    764   Handle<Object> CodeObject() {
    765     DCHECK(!code_object_.is_null());
    766     return code_object_;
    767   }
    768 
    769   // Insert code to verify that the x87 stack has the specified depth (0-7)
    770   void VerifyX87StackDepth(uint32_t depth);
    771 
    772   // Emit code for a truncating division by a constant. The dividend register is
    773   // unchanged, the result is in edx, and eax gets clobbered.
    774   void TruncatingDiv(Register dividend, int32_t divisor);
    775 
    776   // ---------------------------------------------------------------------------
    777   // StatsCounter support
    778 
    779   void SetCounter(StatsCounter* counter, int value);
    780   void IncrementCounter(StatsCounter* counter, int value);
    781   void DecrementCounter(StatsCounter* counter, int value);
    782   void IncrementCounter(Condition cc, StatsCounter* counter, int value);
    783   void DecrementCounter(Condition cc, StatsCounter* counter, int value);
    784 
    785   // ---------------------------------------------------------------------------
    786   // Debugging
    787 
    788   // Calls Abort(msg) if the condition cc is not satisfied.
    789   // Use --debug_code to enable.
    790   void Assert(Condition cc, BailoutReason reason);
    791 
    792   void AssertFastElements(Register elements);
    793 
    794   // Like Assert(), but always enabled.
    795   void Check(Condition cc, BailoutReason reason);
    796 
    797   // Print a message to stdout and abort execution.
    798   void Abort(BailoutReason reason);
    799 
    800   // Check that the stack is aligned.
    801   void CheckStackAlignment();
    802 
    803   // Verify restrictions about code generated in stubs.
    804   void set_generating_stub(bool value) { generating_stub_ = value; }
    805   bool generating_stub() { return generating_stub_; }
    806   void set_has_frame(bool value) { has_frame_ = value; }
    807   bool has_frame() { return has_frame_; }
    808   inline bool AllowThisStubCall(CodeStub* stub);
    809 
    810   // ---------------------------------------------------------------------------
    811   // String utilities.
    812 
    813   // Check whether the instance type represents a flat one-byte string. Jump to
    814   // the label if not. If the instance type can be scratched specify same
    815   // register for both instance type and scratch.
    816   void JumpIfInstanceTypeIsNotSequentialOneByte(
    817       Register instance_type, Register scratch,
    818       Label* on_not_flat_one_byte_string);
    819 
    820   // Checks if both objects are sequential one-byte strings, and jumps to label
    821   // if either is not.
    822   void JumpIfNotBothSequentialOneByteStrings(
    823       Register object1, Register object2, Register scratch1, Register scratch2,
    824       Label* on_not_flat_one_byte_strings);
    825 
    826   // Checks if the given register or operand is a unique name
    827   void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name,
    828                                        Label::Distance distance = Label::kFar) {
    829     JumpIfNotUniqueNameInstanceType(Operand(reg), not_unique_name, distance);
    830   }
    831 
    832   void JumpIfNotUniqueNameInstanceType(Operand operand, Label* not_unique_name,
    833                                        Label::Distance distance = Label::kFar);
    834 
    835   void EmitSeqStringSetCharCheck(Register string, Register index,
    836                                  Register value, uint32_t encoding_mask);
    837 
    838   static int SafepointRegisterStackIndex(Register reg) {
    839     return SafepointRegisterStackIndex(reg.code());
    840   }
    841 
    842   // Load the type feedback vector from a JavaScript frame.
    843   void EmitLoadTypeFeedbackVector(Register vector);
    844 
    845   // Activation support.
    846   void EnterFrame(StackFrame::Type type);
    847   void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
    848   void LeaveFrame(StackFrame::Type type);
    849 
    850   // Expects object in eax and returns map with validated enum cache
    851   // in eax.  Assumes that any other register can be used as a scratch.
    852   void CheckEnumCache(Label* call_runtime);
    853 
    854   // AllocationMemento support. Arrays may have an associated
    855   // AllocationMemento object that can be checked for in order to pretransition
    856   // to another type.
    857   // On entry, receiver_reg should point to the array object.
    858   // scratch_reg gets clobbered.
    859   // If allocation info is present, conditional code is set to equal.
    860   void TestJSArrayForAllocationMemento(Register receiver_reg,
    861                                        Register scratch_reg,
    862                                        Label* no_memento_found);
    863 
    864   void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
    865                                          Register scratch_reg,
    866                                          Label* memento_found) {
    867     Label no_memento_found;
    868     TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
    869                                     &no_memento_found);
    870     j(equal, memento_found);
    871     bind(&no_memento_found);
    872   }
    873 
    874   // Jumps to found label if a prototype map has dictionary elements.
    875   void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
    876                                         Register scratch1, Label* found);
    877 
    878  private:
    879   bool generating_stub_;
    880   bool has_frame_;
    881   // This handle will be patched with the code object on installation.
    882   Handle<Object> code_object_;
    883 
    884   // Helper functions for generating invokes.
    885   void InvokePrologue(const ParameterCount& expected,
    886                       const ParameterCount& actual, Label* done,
    887                       bool* definitely_mismatches, InvokeFlag flag,
    888                       Label::Distance done_distance,
    889                       const CallWrapper& call_wrapper);
    890 
    891   void EnterExitFramePrologue();
    892   void EnterExitFrameEpilogue(int argc, bool save_doubles);
    893 
    894   void LeaveExitFrameEpilogue(bool restore_context);
    895 
    896   // Allocation support helpers.
    897   void LoadAllocationTopHelper(Register result, Register scratch,
    898                                AllocationFlags flags);
    899 
    900   void UpdateAllocationTopHelper(Register result_end, Register scratch,
    901                                  AllocationFlags flags);
    902 
    903   // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
    904   void InNewSpace(Register object, Register scratch, Condition cc,
    905                   Label* condition_met,
    906                   Label::Distance condition_met_distance = Label::kFar);
    907 
    908   // Helper for finding the mark bits for an address.  Afterwards, the
    909   // bitmap register points at the word with the mark bits and the mask
    910   // the position of the first bit.  Uses ecx as scratch and leaves addr_reg
    911   // unchanged.
    912   inline void GetMarkBits(Register addr_reg, Register bitmap_reg,
    913                           Register mask_reg);
    914 
    915   // Compute memory operands for safepoint stack slots.
    916   Operand SafepointRegisterSlot(Register reg);
    917   static int SafepointRegisterStackIndex(int reg_code);
    918 
    919   // Needs access to SafepointRegisterStackIndex for compiled frame
    920   // traversal.
    921   friend class StandardFrame;
    922 };
    923 
    924 // The code patcher is used to patch (typically) small parts of code e.g. for
    925 // debugging and other types of instrumentation. When using the code patcher
    926 // the exact number of bytes specified must be emitted. Is not legal to emit
    927 // relocation information. If any of these constraints are violated it causes
    928 // an assertion.
    929 class CodePatcher {
    930  public:
    931   CodePatcher(Isolate* isolate, byte* address, int size);
    932   ~CodePatcher();
    933 
    934   // Macro assembler to emit code.
    935   MacroAssembler* masm() { return &masm_; }
    936 
    937  private:
    938   byte* address_;        // The address of the code being patched.
    939   int size_;             // Number of bytes of the expected patch size.
    940   MacroAssembler masm_;  // Macro assembler used to generate the code.
    941 };
    942 
    943 // -----------------------------------------------------------------------------
    944 // Static helper functions.
    945 
    946 // Generate an Operand for loading a field from an object.
    947 inline Operand FieldOperand(Register object, int offset) {
    948   return Operand(object, offset - kHeapObjectTag);
    949 }
    950 
    951 // Generate an Operand for loading an indexed field from an object.
    952 inline Operand FieldOperand(Register object, Register index, ScaleFactor scale,
    953                             int offset) {
    954   return Operand(object, index, scale, offset - kHeapObjectTag);
    955 }
    956 
    957 inline Operand FixedArrayElementOperand(Register array, Register index_as_smi,
    958                                         int additional_offset = 0) {
    959   int offset = FixedArray::kHeaderSize + additional_offset * kPointerSize;
    960   return FieldOperand(array, index_as_smi, times_half_pointer_size, offset);
    961 }
    962 
    963 inline Operand ContextOperand(Register context, int index) {
    964   return Operand(context, Context::SlotOffset(index));
    965 }
    966 
    967 inline Operand ContextOperand(Register context, Register index) {
    968   return Operand(context, index, times_pointer_size, Context::SlotOffset(0));
    969 }
    970 
    971 inline Operand NativeContextOperand() {
    972   return ContextOperand(esi, Context::NATIVE_CONTEXT_INDEX);
    973 }
    974 
    975 #ifdef GENERATED_CODE_COVERAGE
    976 extern void LogGeneratedCodeCoverage(const char* file_line);
    977 #define CODE_COVERAGE_STRINGIFY(x) #x
    978 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
    979 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
    980 #define ACCESS_MASM(masm) {                                               \
    981     byte* ia32_coverage_function =                                        \
    982         reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
    983     masm->pushfd();                                                       \
    984     masm->pushad();                                                       \
    985     masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__)));         \
    986     masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY);         \
    987     masm->pop(eax);                                                       \
    988     masm->popad();                                                        \
    989     masm->popfd();                                                        \
    990   }                                                                       \
    991   masm->
    992 #else
    993 #define ACCESS_MASM(masm) masm->
    994 #endif
    995 
    996 }  // namespace internal
    997 }  // namespace v8
    998 
    999 #endif  // V8_X87_MACRO_ASSEMBLER_X87_H_
   1000