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