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 INCLUDED_FROM_MACRO_ASSEMBLER_H
6 #error This header must be included via macro-assembler.h
7 #endif
8 
9 #ifndef V8_CODEGEN_IA32_MACRO_ASSEMBLER_IA32_H_
10 #define V8_CODEGEN_IA32_MACRO_ASSEMBLER_IA32_H_
11 
12 #include <stdint.h>
13 
14 #include "include/v8-internal.h"
15 #include "src/base/logging.h"
16 #include "src/base/macros.h"
17 #include "src/builtins/builtins.h"
18 #include "src/codegen/assembler.h"
19 #include "src/codegen/bailout-reason.h"
20 #include "src/codegen/cpu-features.h"
21 #include "src/codegen/ia32/assembler-ia32.h"
22 #include "src/codegen/ia32/register-ia32.h"
23 #include "src/codegen/label.h"
24 #include "src/codegen/reglist.h"
25 #include "src/codegen/reloc-info.h"
26 #include "src/codegen/shared-ia32-x64/macro-assembler-shared-ia32-x64.h"
27 #include "src/codegen/turbo-assembler.h"
28 #include "src/common/globals.h"
29 #include "src/execution/frames.h"
30 #include "src/handles/handles.h"
31 #include "src/objects/heap-object.h"
32 #include "src/objects/smi.h"
33 #include "src/roots/roots.h"
34 #include "src/runtime/runtime.h"
35 
36 namespace v8 {
37 namespace internal {
38 
39 class Code;
40 class ExternalReference;
41 class StatsCounter;
42 
43 // Convenience for platform-independent signatures.  We do not normally
44 // distinguish memory operands from other operands on ia32.
45 using MemOperand = Operand;
46 
47 // TODO(victorgomes): Move definition to macro-assembler.h, once all other
48 // platforms are updated.
49 enum class StackLimitKind { kInterruptStackLimit, kRealStackLimit };
50 
51 // Convenient class to access arguments below the stack pointer.
52 class StackArgumentsAccessor {
53  public:
54   // argc = the number of arguments not including the receiver.
StackArgumentsAccessor(Register argc)55   explicit StackArgumentsAccessor(Register argc) : argc_(argc) {
56     DCHECK_NE(argc_, no_reg);
57   }
58 
59   // Argument 0 is the receiver (despite argc not including the receiver).
operator [](int index) const60   Operand operator[](int index) const { return GetArgumentOperand(index); }
61 
62   Operand GetArgumentOperand(int index) const;
GetReceiverOperand() const63   Operand GetReceiverOperand() const { return GetArgumentOperand(0); }
64 
65  private:
66   const Register argc_;
67 
68   DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
69 };
70 
71 class V8_EXPORT_PRIVATE TurboAssembler
72     : public SharedTurboAssemblerBase<TurboAssembler> {
73  public:
74   using SharedTurboAssemblerBase<TurboAssembler>::SharedTurboAssemblerBase;
75 
76   void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
77                      Label* condition_met,
78                      Label::Distance condition_met_distance = Label::kFar);
79 
80   // Activation support.
81   void EnterFrame(StackFrame::Type type);
EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg)82   void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg) {
83     // Out-of-line constant pool not implemented on ia32.
84     UNREACHABLE();
85   }
86   void LeaveFrame(StackFrame::Type type);
87 
88 // Allocate stack space of given size (i.e. decrement {esp} by the value
89 // stored in the given register, or by a constant). If you need to perform a
90 // stack check, do it before calling this function because this function may
91 // write into the newly allocated space. It may also overwrite the given
92 // register's value, in the version that takes a register.
93 #ifdef V8_OS_WIN
94   void AllocateStackSpace(Register bytes_scratch);
95   void AllocateStackSpace(int bytes);
96 #else
AllocateStackSpace(Register bytes)97   void AllocateStackSpace(Register bytes) { sub(esp, bytes); }
AllocateStackSpace(int bytes)98   void AllocateStackSpace(int bytes) {
99     DCHECK_GE(bytes, 0);
100     if (bytes == 0) return;
101     sub(esp, Immediate(bytes));
102   }
103 #endif
104 
105   // Print a message to stdout and abort execution.
106   void Abort(AbortReason reason);
107 
108   // Calls Abort(msg) if the condition cc is not satisfied.
109   // Use --debug_code to enable.
110   void Assert(Condition cc, AbortReason reason);
111 
112   // Like Assert(), but without condition.
113   // Use --debug_code to enable.
114   void AssertUnreachable(AbortReason reason);
115 
116   // Like Assert(), but always enabled.
117   void Check(Condition cc, AbortReason reason);
118 
119   // Check that the stack is aligned.
120   void CheckStackAlignment();
121 
122   // Move a constant into a destination using the most efficient encoding.
Move(Register dst, int32_t x)123   void Move(Register dst, int32_t x) {
124     if (x == 0) {
125       xor_(dst, dst);
126     } else {
127       mov(dst, Immediate(x));
128     }
129   }
130   void Move(Register dst, const Immediate& src);
Move(Register dst, Smi src)131   void Move(Register dst, Smi src) { Move(dst, Immediate(src)); }
132   void Move(Register dst, Handle<HeapObject> src);
133   void Move(Register dst, Register src);
134   void Move(Register dst, Operand src);
135   void Move(Operand dst, const Immediate& src);
136 
137   // Move an immediate into an XMM register.
138   void Move(XMMRegister dst, uint32_t src);
139   void Move(XMMRegister dst, uint64_t src);
Move(XMMRegister dst, float src)140   void Move(XMMRegister dst, float src) { Move(dst, bit_cast<uint32_t>(src)); }
Move(XMMRegister dst, double src)141   void Move(XMMRegister dst, double src) { Move(dst, bit_cast<uint64_t>(src)); }
142 
143   Operand EntryFromBuiltinAsOperand(Builtin builtin);
144 
Call(Register reg)145   void Call(Register reg) { call(reg); }
Call(Operand op)146   void Call(Operand op) { call(op); }
Call(Label* target)147   void Call(Label* target) { call(target); }
148   void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
149 
150   // Load the builtin given by the Smi in |builtin_index| into the same
151   // register.
152   void LoadEntryFromBuiltinIndex(Register builtin_index);
153   void CallBuiltinByIndex(Register builtin_index);
154   void CallBuiltin(Builtin builtin);
155 
156   void LoadCodeObjectEntry(Register destination, Register code_object);
157   void CallCodeObject(Register code_object);
158   void JumpCodeObject(Register code_object,
159                       JumpMode jump_mode = JumpMode::kJump);
160   void Jump(const ExternalReference& reference);
161 
162   void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
163 
164   void LoadMap(Register destination, Register object);
165 
166   void Trap();
167   void DebugBreak();
168 
169   void CallForDeoptimization(Builtin target, int deopt_id, Label* exit,
170                              DeoptimizeKind kind, Label* ret,
171                              Label* jump_deoptimization_entry_label);
172 
173   // Jump the register contains a smi.
JumpIfSmi(Register value, Label* smi_label, Label::Distance distance = Label::kFar)174   inline void JumpIfSmi(Register value, Label* smi_label,
175                         Label::Distance distance = Label::kFar) {
176     test(value, Immediate(kSmiTagMask));
177     j(zero, smi_label, distance);
178   }
179   // Jump if the operand is a smi.
JumpIfSmi(Operand value, Label* smi_label, Label::Distance distance = Label::kFar)180   inline void JumpIfSmi(Operand value, Label* smi_label,
181                         Label::Distance distance = Label::kFar) {
182     test(value, Immediate(kSmiTagMask));
183     j(zero, smi_label, distance);
184   }
185 
JumpIfEqual(Register a, int32_t b, Label* dest)186   void JumpIfEqual(Register a, int32_t b, Label* dest) {
187     cmp(a, Immediate(b));
188     j(equal, dest);
189   }
190 
JumpIfLessThan(Register a, int32_t b, Label* dest)191   void JumpIfLessThan(Register a, int32_t b, Label* dest) {
192     cmp(a, Immediate(b));
193     j(less, dest);
194   }
195 
SmiUntag(Register reg)196   void SmiUntag(Register reg) { sar(reg, kSmiTagSize); }
SmiUntag(Register output, Register value)197   void SmiUntag(Register output, Register value) {
198     mov(output, value);
199     SmiUntag(output);
200   }
201 
SmiToInt32(Register reg)202   void SmiToInt32(Register reg) { SmiUntag(reg); }
203 
204   // Before calling a C-function from generated code, align arguments on stack.
205   // After aligning the frame, arguments must be stored in esp[0], esp[4],
206   // etc., not pushed. The argument count assumes all arguments are word sized.
207   // Some compilers/platforms require the stack to be aligned when calling
208   // C++ code.
209   // Needs a scratch register to do some arithmetic. This register will be
210   // trashed.
211   void PrepareCallCFunction(int num_arguments, Register scratch);
212 
213   // Calls a C function and cleans up the space for arguments allocated
214   // by PrepareCallCFunction. The called function is not allowed to trigger a
215   // garbage collection, since that might move the code and invalidate the
216   // return address (unless this is somehow accounted for by the called
217   // function).
218   void CallCFunction(ExternalReference function, int num_arguments);
219   void CallCFunction(Register function, int num_arguments);
220 
221   void ShlPair(Register high, Register low, uint8_t imm8);
222   void ShlPair_cl(Register high, Register low);
223   void ShrPair(Register high, Register low, uint8_t imm8);
224   void ShrPair_cl(Register high, Register low);
225   void SarPair(Register high, Register low, uint8_t imm8);
226   void SarPair_cl(Register high, Register low);
227 
228   // Generates function and stub prologue code.
229   void StubPrologue(StackFrame::Type type);
230   void Prologue();
231 
232   // Helpers for argument handling
233   enum ArgumentsCountMode { kCountIncludesReceiver, kCountExcludesReceiver };
234   enum ArgumentsCountType { kCountIsInteger, kCountIsSmi, kCountIsBytes };
235   void DropArguments(Register count, Register scratch, ArgumentsCountType type,
236                      ArgumentsCountMode mode);
237   void DropArgumentsAndPushNewReceiver(Register argc, Register receiver,
238                                        Register scratch,
239                                        ArgumentsCountType type,
240                                        ArgumentsCountMode mode);
241   void DropArgumentsAndPushNewReceiver(Register argc, Operand receiver,
242                                        Register scratch,
243                                        ArgumentsCountType type,
244                                        ArgumentsCountMode mode);
245 
Lzcnt(Register dst, Register src)246   void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); }
247   void Lzcnt(Register dst, Operand src);
248 
Tzcnt(Register dst, Register src)249   void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); }
250   void Tzcnt(Register dst, Operand src);
251 
Popcnt(Register dst, Register src)252   void Popcnt(Register dst, Register src) { Popcnt(dst, Operand(src)); }
253   void Popcnt(Register dst, Operand src);
254 
PushReturnAddressFrom(Register src)255   void PushReturnAddressFrom(Register src) { push(src); }
PopReturnAddressTo(Register dst)256   void PopReturnAddressTo(Register dst) { pop(dst); }
257 
PushReturnAddressFrom(XMMRegister src, Register scratch)258   void PushReturnAddressFrom(XMMRegister src, Register scratch) {
259     Push(src, scratch);
260   }
PopReturnAddressTo(XMMRegister dst, Register scratch)261   void PopReturnAddressTo(XMMRegister dst, Register scratch) {
262     Pop(dst, scratch);
263   }
264 
265   void Ret();
266 
267   // Root register utility functions.
268 
269   void InitializeRootRegister();
270 
271   Operand RootAsOperand(RootIndex index);
272   void LoadRoot(Register destination, RootIndex index) final;
273 
274   // Indirect root-relative loads.
275   void LoadFromConstantsTable(Register destination, int constant_index) final;
276   void LoadRootRegisterOffset(Register destination, intptr_t offset) final;
277   void LoadRootRelative(Register destination, int32_t offset) final;
278 
279   void PushPC();
280 
281   enum class PushArrayOrder { kNormal, kReverse };
282   // `array` points to the first element (the lowest address).
283   // `array` and `size` are not modified.
284   void PushArray(Register array, Register size, Register scratch,
285                  PushArrayOrder order = PushArrayOrder::kNormal);
286 
287   // Operand pointing to an external reference.
288   // May emit code to set up the scratch register. The operand is
289   // only guaranteed to be correct as long as the scratch register
290   // isn't changed.
291   // If the operand is used more than once, use a scratch register
292   // that is guaranteed not to be clobbered.
293   Operand ExternalReferenceAsOperand(ExternalReference reference,
294                                      Register scratch);
295   Operand ExternalReferenceAddressAsOperand(ExternalReference reference);
296   Operand HeapObjectAsOperand(Handle<HeapObject> object);
297 
298   void LoadAddress(Register destination, ExternalReference source);
299 
300   void CompareRoot(Register with, RootIndex index);
301   void CompareRoot(Register with, Register scratch, RootIndex index);
302 
303   // Return and drop arguments from stack, where the number of arguments
304   // may be bigger than 2^16 - 1.  Requires a scratch register.
305   void Ret(int bytes_dropped, Register scratch);
306 
307   void PextrdPreSse41(Register dst, XMMRegister src, uint8_t imm8);
PinsrdPreSse41(XMMRegister dst, Register src, uint8_t imm8, uint32_t* load_pc_offset)308   void PinsrdPreSse41(XMMRegister dst, Register src, uint8_t imm8,
309                       uint32_t* load_pc_offset) {
310     PinsrdPreSse41(dst, Operand(src), imm8, load_pc_offset);
311   }
312   void PinsrdPreSse41(XMMRegister dst, Operand src, uint8_t imm8,
313                       uint32_t* load_pc_offset);
314 
315   // Expression support
316   // cvtsi2sd instruction only writes to the low 64-bit of dst register, which
317   // hinders register renaming and makes dependence chains longer. So we use
318   // xorps to clear the dst register before cvtsi2sd to solve this issue.
Cvtsi2ss(XMMRegister dst, Register src)319   void Cvtsi2ss(XMMRegister dst, Register src) { Cvtsi2ss(dst, Operand(src)); }
320   void Cvtsi2ss(XMMRegister dst, Operand src);
Cvtsi2sd(XMMRegister dst, Register src)321   void Cvtsi2sd(XMMRegister dst, Register src) { Cvtsi2sd(dst, Operand(src)); }
322   void Cvtsi2sd(XMMRegister dst, Operand src);
323 
Cvtui2ss(XMMRegister dst, Register src, Register tmp)324   void Cvtui2ss(XMMRegister dst, Register src, Register tmp) {
325     Cvtui2ss(dst, Operand(src), tmp);
326   }
327   void Cvtui2ss(XMMRegister dst, Operand src, Register tmp);
Cvttss2ui(Register dst, XMMRegister src, XMMRegister tmp)328   void Cvttss2ui(Register dst, XMMRegister src, XMMRegister tmp) {
329     Cvttss2ui(dst, Operand(src), tmp);
330   }
331   void Cvttss2ui(Register dst, Operand src, XMMRegister tmp);
Cvtui2sd(XMMRegister dst, Register src, Register scratch)332   void Cvtui2sd(XMMRegister dst, Register src, Register scratch) {
333     Cvtui2sd(dst, Operand(src), scratch);
334   }
335   void Cvtui2sd(XMMRegister dst, Operand src, Register scratch);
Cvttsd2ui(Register dst, XMMRegister src, XMMRegister tmp)336   void Cvttsd2ui(Register dst, XMMRegister src, XMMRegister tmp) {
337     Cvttsd2ui(dst, Operand(src), tmp);
338   }
339   void Cvttsd2ui(Register dst, Operand src, XMMRegister tmp);
340 
Push(Register src)341   void Push(Register src) { push(src); }
Push(Operand src)342   void Push(Operand src) { push(src); }
343   void Push(Immediate value);
Push(Handle<HeapObject> handle)344   void Push(Handle<HeapObject> handle) { push(Immediate(handle)); }
Push(Smi smi)345   void Push(Smi smi) { Push(Immediate(smi)); }
Push(XMMRegister src, Register scratch)346   void Push(XMMRegister src, Register scratch) {
347     movd(scratch, src);
348     push(scratch);
349   }
350 
Pop(Register dst)351   void Pop(Register dst) { pop(dst); }
Pop(Operand dst)352   void Pop(Operand dst) { pop(dst); }
Pop(XMMRegister dst, Register scratch)353   void Pop(XMMRegister dst, Register scratch) {
354     pop(scratch);
355     movd(dst, scratch);
356   }
357 
358   void MaybeSaveRegisters(RegList registers);
359   void MaybeRestoreRegisters(RegList registers);
360 
361   void CallEphemeronKeyBarrier(Register object, Register slot_address,
362                                SaveFPRegsMode fp_mode);
363 
364   void CallRecordWriteStubSaveRegisters(
365       Register object, Register slot_address,
366       RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
367       StubCallMode mode = StubCallMode::kCallBuiltinPointer);
368   void CallRecordWriteStub(
369       Register object, Register slot_address,
370       RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
371       StubCallMode mode = StubCallMode::kCallBuiltinPointer);
372 
373   // Calculate how much stack space (in bytes) are required to store caller
374   // registers excluding those specified in the arguments.
375   int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
376                                       Register exclusion1 = no_reg,
377                                       Register exclusion2 = no_reg,
378                                       Register exclusion3 = no_reg) const;
379 
380   // PushCallerSaved and PopCallerSaved do not arrange the registers in any
381   // particular order so they are not useful for calls that can cause a GC.
382   // The caller can exclude up to 3 registers that do not need to be saved and
383   // restored.
384 
385   // Push caller saved registers on the stack, and return the number of bytes
386   // stack pointer is adjusted.
387   int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
388                       Register exclusion2 = no_reg,
389                       Register exclusion3 = no_reg);
390   // Restore caller saved registers from the stack, and return the number of
391   // bytes stack pointer is adjusted.
392   int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
393                      Register exclusion2 = no_reg,
394                      Register exclusion3 = no_reg);
395 
396   // Compute the start of the generated instruction stream from the current PC.
397   // This is an alternative to embedding the {CodeObject} handle as a reference.
398   void ComputeCodeStartAddress(Register dst);
399 
400   // Control-flow integrity:
401 
402   // Define a function entrypoint. This doesn't emit any code for this
403   // architecture, as control-flow integrity is not supported for it.
CodeEntry()404   void CodeEntry() {}
405   // Define an exception handler.
ExceptionHandler()406   void ExceptionHandler() {}
407   // Define an exception handler and bind a label.
BindExceptionHandler(Label* label)408   void BindExceptionHandler(Label* label) { bind(label); }
409 
410  protected:
411   // Drops arguments assuming that the return address was already popped.
412   void DropArguments(Register count, ArgumentsCountType type = kCountIsInteger,
413                      ArgumentsCountMode mode = kCountExcludesReceiver);
414 };
415 
416 // MacroAssembler implements a collection of frequently used macros.
417 class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
418  public:
419   using TurboAssembler::TurboAssembler;
420 
421   void PushRoot(RootIndex index);
422 
423   // Compare the object in a register to a value and jump if they are equal.
JumpIfRoot(Register with, RootIndex index, Label* if_equal, Label::Distance if_equal_distance = Label::kFar)424   void JumpIfRoot(Register with, RootIndex index, Label* if_equal,
425                   Label::Distance if_equal_distance = Label::kFar) {
426     CompareRoot(with, index);
427     j(equal, if_equal, if_equal_distance);
428   }
429 
430   // Compare the object in a register to a value and jump if they are not equal.
JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal, Label::Distance if_not_equal_distance = Label::kFar)431   void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal,
432                      Label::Distance if_not_equal_distance = Label::kFar) {
433     CompareRoot(with, index);
434     j(not_equal, if_not_equal, if_not_equal_distance);
435   }
436 
437   // Checks if value is in range [lower_limit, higher_limit] using a single
438   // comparison. Flags CF=1 or ZF=1 indicate the value is in the range
439   // (condition below_equal). It is valid, that |value| == |scratch| as far as
440   // this function is concerned.
441   void CompareRange(Register value, unsigned lower_limit, unsigned higher_limit,
442                     Register scratch);
443   void JumpIfIsInRange(Register value, unsigned lower_limit,
444                        unsigned higher_limit, Register scratch,
445                        Label* on_in_range,
446                        Label::Distance near_jump = Label::kFar);
447 
448   // ---------------------------------------------------------------------------
449   // GC Support
450   // Notify the garbage collector that we wrote a pointer into an object.
451   // |object| is the object being stored into, |value| is the object being
452   // stored.  value and scratch registers are clobbered by the operation.
453   // The offset is the offset from the start of the object, not the offset from
454   // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
455   void RecordWriteField(
456       Register object, int offset, Register value, Register scratch,
457       SaveFPRegsMode save_fp,
458       RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
459       SmiCheck smi_check = SmiCheck::kInline);
460 
461   // For page containing |object| mark region covering |address|
462   // dirty. |object| is the object being stored into, |value| is the
463   // object being stored. The address and value registers are clobbered by the
464   // operation. RecordWrite filters out smis so it does not update the
465   // write barrier if the value is a smi.
466   void RecordWrite(
467       Register object, Register address, Register value, SaveFPRegsMode save_fp,
468       RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
469       SmiCheck smi_check = SmiCheck::kInline);
470 
471   // Enter specific kind of exit frame. Expects the number of
472   // arguments in register eax and sets up the number of arguments in
473   // register edi and the pointer to the first argument in register
474   // esi.
475   void EnterExitFrame(int argc, bool save_doubles, StackFrame::Type frame_type);
476 
477   void EnterApiExitFrame(int argc, Register scratch);
478 
479   // Leave the current exit frame. Expects the return value in
480   // register eax:edx (untouched) and the pointer to the first
481   // argument in register esi (if pop_arguments == true).
482   void LeaveExitFrame(bool save_doubles, bool pop_arguments = true);
483 
484   // Leave the current exit frame. Expects the return value in
485   // register eax (untouched).
486   void LeaveApiExitFrame();
487 
488   // Load the global proxy from the current context.
489   void LoadGlobalProxy(Register dst);
490 
491   // Load a value from the native context with a given index.
492   void LoadNativeContextSlot(Register dst, int index);
493 
494   // ---------------------------------------------------------------------------
495   // JavaScript invokes
496 
497   // Invoke the JavaScript function code by either calling or jumping.
498 
499   void InvokeFunctionCode(Register function, Register new_target,
500                           Register expected_parameter_count,
501                           Register actual_parameter_count, InvokeType type);
502 
503   // On function call, call into the debugger.
504   // This may clobber ecx.
505   void CallDebugOnFunctionCall(Register fun, Register new_target,
506                                Register expected_parameter_count,
507                                Register actual_parameter_count);
508 
509   // Invoke the JavaScript function in the given register. Changes the
510   // current context to the context in the function before invoking.
511   void InvokeFunction(Register function, Register new_target,
512                       Register actual_parameter_count, InvokeType type);
513 
514   // Compare object type for heap object.
515   // Incoming register is heap_object and outgoing register is map.
516   void CmpObjectType(Register heap_object, InstanceType type, Register map);
517 
518   // Compare instance type for map.
519   void CmpInstanceType(Register map, InstanceType type);
520 
521   // Compare instance type ranges for a map (lower_limit and higher_limit
522   // inclusive).
523   //
524   // Always use unsigned comparisons: below_equal for a positive
525   // result.
526   void CmpInstanceTypeRange(Register map, Register instance_type_out,
527                             Register scratch, InstanceType lower_limit,
528                             InstanceType higher_limit);
529 
530   // Smi tagging support.
SmiTag(Register reg)531   void SmiTag(Register reg) {
532     STATIC_ASSERT(kSmiTag == 0);
533     STATIC_ASSERT(kSmiTagSize == 1);
534     add(reg, reg);
535   }
536 
537   // Jump if register contain a non-smi.
JumpIfNotSmi(Register value, Label* not_smi_label, Label::Distance distance = Label::kFar)538   inline void JumpIfNotSmi(Register value, Label* not_smi_label,
539                            Label::Distance distance = Label::kFar) {
540     test(value, Immediate(kSmiTagMask));
541     j(not_zero, not_smi_label, distance);
542   }
543   // Jump if the operand is not a smi.
JumpIfNotSmi(Operand value, Label* smi_label, Label::Distance distance = Label::kFar)544   inline void JumpIfNotSmi(Operand value, Label* smi_label,
545                            Label::Distance distance = Label::kFar) {
546     test(value, Immediate(kSmiTagMask));
547     j(not_zero, smi_label, distance);
548   }
549 
550   template <typename Field>
DecodeField(Register reg)551   void DecodeField(Register reg) {
552     static const int shift = Field::kShift;
553     static const int mask = Field::kMask >> Field::kShift;
554     if (shift != 0) {
555       sar(reg, shift);
556     }
557     and_(reg, Immediate(mask));
558   }
559 
560   // Abort execution if argument is not a smi, enabled via --debug-code.
561   void AssertSmi(Register object);
562 
563   // Abort execution if argument is a smi, enabled via --debug-code.
564   void AssertNotSmi(Register object);
565 
566   // Abort execution if argument is not a JSFunction, enabled via --debug-code.
567   void AssertFunction(Register object, Register scratch);
568 
569   // Abort execution if argument is not a callable JSFunction, enabled via
570   // --debug-code.
571   void AssertCallableFunction(Register object, Register scratch);
572 
573   // Abort execution if argument is not a Constructor, enabled via --debug-code.
574   void AssertConstructor(Register object);
575 
576   // Abort execution if argument is not a JSBoundFunction,
577   // enabled via --debug-code.
578   void AssertBoundFunction(Register object);
579 
580   // Abort execution if argument is not a JSGeneratorObject (or subclass),
581   // enabled via --debug-code.
582   void AssertGeneratorObject(Register object);
583 
584   // Abort execution if argument is not undefined or an AllocationSite, enabled
585   // via --debug-code.
586   void AssertUndefinedOrAllocationSite(Register object, Register scratch);
587 
588   // ---------------------------------------------------------------------------
589   // Exception handling
590 
591   // Push a new stack handler and link it into stack handler chain.
592   void PushStackHandler(Register scratch);
593 
594   // Unlink the stack handler on top of the stack from the stack handler chain.
595   void PopStackHandler(Register scratch);
596 
597   // ---------------------------------------------------------------------------
598   // Runtime calls
599 
600   // Call a runtime routine.
601   void CallRuntime(const Runtime::Function* f, int num_arguments,
602                    SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore);
603 
604   // Convenience function: Same as above, but takes the fid instead.
CallRuntime(Runtime::FunctionId fid, SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore)605   void CallRuntime(Runtime::FunctionId fid,
606                    SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
607     const Runtime::Function* function = Runtime::FunctionForId(fid);
608     CallRuntime(function, function->nargs, save_doubles);
609   }
610 
611   // Convenience function: Same as above, but takes the fid instead.
CallRuntime(Runtime::FunctionId fid, int num_arguments, SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore)612   void CallRuntime(Runtime::FunctionId fid, int num_arguments,
613                    SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
614     CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
615   }
616 
617   // Convenience function: tail call a runtime routine (jump).
618   void TailCallRuntime(Runtime::FunctionId fid);
619 
620   // Jump to a runtime routine.
621   void JumpToExternalReference(const ExternalReference& ext,
622                                bool builtin_exit_frame = false);
623 
624   // Generates a trampoline to jump to the off-heap instruction stream.
625   void JumpToOffHeapInstructionStream(Address entry);
626 
627   // ---------------------------------------------------------------------------
628   // Utilities
629 
630   // Emit code to discard a non-negative number of pointer-sized elements
631   // from the stack, clobbering only the esp register.
632   void Drop(int element_count);
633 
634   // ---------------------------------------------------------------------------
635   // In-place weak references.
636   void LoadWeakValue(Register in_out, Label* target_if_cleared);
637 
638   // ---------------------------------------------------------------------------
639   // StatsCounter support
640 
IncrementCounter(StatsCounter* counter, int value, Register scratch)641   void IncrementCounter(StatsCounter* counter, int value, Register scratch) {
642     if (!FLAG_native_code_counters) return;
643     EmitIncrementCounter(counter, value, scratch);
644   }
645   void EmitIncrementCounter(StatsCounter* counter, int value, Register scratch);
DecrementCounter(StatsCounter* counter, int value, Register scratch)646   void DecrementCounter(StatsCounter* counter, int value, Register scratch) {
647     if (!FLAG_native_code_counters) return;
648     EmitDecrementCounter(counter, value, scratch);
649   }
650   void EmitDecrementCounter(StatsCounter* counter, int value, Register scratch);
651 
652   // ---------------------------------------------------------------------------
653   // Stack limit utilities
654   void CompareStackLimit(Register with, StackLimitKind kind);
655   void StackOverflowCheck(Register num_args, Register scratch,
656                           Label* stack_overflow, bool include_receiver = false);
657 
658  private:
659   // Helper functions for generating invokes.
660   void InvokePrologue(Register expected_parameter_count,
661                       Register actual_parameter_count, Label* done,
662                       InvokeType type);
663 
664   void EnterExitFramePrologue(StackFrame::Type frame_type, Register scratch);
665   void EnterExitFrameEpilogue(int argc, bool save_doubles);
666 
667   void LeaveExitFrameEpilogue();
668 
669   DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler);
670 };
671 
672 // -----------------------------------------------------------------------------
673 // Static helper functions.
674 
675 // Generate an Operand for loading a field from an object.
FieldOperand(Register object, int offset)676 inline Operand FieldOperand(Register object, int offset) {
677   return Operand(object, offset - kHeapObjectTag);
678 }
679 
680 // Generate an Operand for loading an indexed field from an object.
FieldOperand(Register object, Register index, ScaleFactor scale, int offset)681 inline Operand FieldOperand(Register object, Register index, ScaleFactor scale,
682                             int offset) {
683   return Operand(object, index, scale, offset - kHeapObjectTag);
684 }
685 
686 #define ACCESS_MASM(masm) masm->
687 
688 }  // namespace internal
689 }  // namespace v8
690 
691 #endif  // V8_CODEGEN_IA32_MACRO_ASSEMBLER_IA32_H_
692