The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / ia32 / macro-assembler-ia32.h @ f230a1cf

History | View | Annotate | Download (45.6 KB)

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
// Convenience for platform-independent signatures.  We do not normally
39
// distinguish memory operands from other operands on ia32.
40
typedef Operand MemOperand;
41

    
42
enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
43
enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
44

    
45

    
46
enum RegisterValueType {
47
  REGISTER_VALUE_IS_SMI,
48
  REGISTER_VALUE_IS_INT32
49
};
50

    
51

    
52
bool AreAliased(Register r1, Register r2, Register r3, Register r4);
53

    
54

    
55
// MacroAssembler implements a collection of frequently used macros.
56
class MacroAssembler: public Assembler {
57
 public:
58
  // The isolate parameter can be NULL if the macro assembler should
59
  // not use isolate-dependent functionality. In this case, it's the
60
  // responsibility of the caller to never invoke such function on the
61
  // macro assembler.
62
  MacroAssembler(Isolate* isolate, void* buffer, int size);
63

    
64
  // Operations on roots in the root-array.
65
  void LoadRoot(Register destination, Heap::RootListIndex index);
66
  void StoreRoot(Register source, Register scratch, Heap::RootListIndex index);
67
  void CompareRoot(Register with, Register scratch, Heap::RootListIndex index);
68
  // These methods can only be used with constant roots (i.e. non-writable
69
  // and not in new space).
70
  void CompareRoot(Register with, Heap::RootListIndex index);
71
  void CompareRoot(const Operand& with, Heap::RootListIndex index);
72

    
73
  // ---------------------------------------------------------------------------
74
  // GC Support
75
  enum RememberedSetFinalAction {
76
    kReturnAtEnd,
77
    kFallThroughAtEnd
78
  };
79

    
80
  // Record in the remembered set the fact that we have a pointer to new space
81
  // at the address pointed to by the addr register.  Only works if addr is not
82
  // in new space.
83
  void RememberedSetHelper(Register object,  // Used for debug code.
84
                           Register addr,
85
                           Register scratch,
86
                           SaveFPRegsMode save_fp,
87
                           RememberedSetFinalAction and_then);
88

    
89
  void CheckPageFlag(Register object,
90
                     Register scratch,
91
                     int mask,
92
                     Condition cc,
93
                     Label* condition_met,
94
                     Label::Distance condition_met_distance = Label::kFar);
95

    
96
  void CheckPageFlagForMap(
97
      Handle<Map> map,
98
      int mask,
99
      Condition cc,
100
      Label* condition_met,
101
      Label::Distance condition_met_distance = Label::kFar);
102

    
103
  void CheckMapDeprecated(Handle<Map> map,
104
                          Register scratch,
105
                          Label* if_deprecated);
106

    
107
  // Check if object is in new space.  Jumps if the object is not in new space.
108
  // The register scratch can be object itself, but scratch will be clobbered.
109
  void JumpIfNotInNewSpace(Register object,
110
                           Register scratch,
111
                           Label* branch,
112
                           Label::Distance distance = Label::kFar) {
113
    InNewSpace(object, scratch, zero, branch, distance);
114
  }
115

    
116
  // Check if object is in new space.  Jumps if the object is in new space.
117
  // The register scratch can be object itself, but it will be clobbered.
118
  void JumpIfInNewSpace(Register object,
119
                        Register scratch,
120
                        Label* branch,
121
                        Label::Distance distance = Label::kFar) {
122
    InNewSpace(object, scratch, not_zero, branch, distance);
123
  }
124

    
125
  // Check if an object has a given incremental marking color.  Also uses ecx!
126
  void HasColor(Register object,
127
                Register scratch0,
128
                Register scratch1,
129
                Label* has_color,
130
                Label::Distance has_color_distance,
131
                int first_bit,
132
                int second_bit);
133

    
134
  void JumpIfBlack(Register object,
135
                   Register scratch0,
136
                   Register scratch1,
137
                   Label* on_black,
138
                   Label::Distance on_black_distance = Label::kFar);
139

    
140
  // Checks the color of an object.  If the object is already grey or black
141
  // then we just fall through, since it is already live.  If it is white and
142
  // we can determine that it doesn't need to be scanned, then we just mark it
143
  // black and fall through.  For the rest we jump to the label so the
144
  // incremental marker can fix its assumptions.
145
  void EnsureNotWhite(Register object,
146
                      Register scratch1,
147
                      Register scratch2,
148
                      Label* object_is_white_and_not_data,
149
                      Label::Distance distance);
150

    
151
  // Notify the garbage collector that we wrote a pointer into an object.
152
  // |object| is the object being stored into, |value| is the object being
153
  // stored.  value and scratch registers are clobbered by the operation.
154
  // The offset is the offset from the start of the object, not the offset from
155
  // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
156
  void RecordWriteField(
157
      Register object,
158
      int offset,
159
      Register value,
160
      Register scratch,
161
      SaveFPRegsMode save_fp,
162
      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
163
      SmiCheck smi_check = INLINE_SMI_CHECK);
164

    
165
  // As above, but the offset has the tag presubtracted.  For use with
166
  // Operand(reg, off).
167
  void RecordWriteContextSlot(
168
      Register context,
169
      int offset,
170
      Register value,
171
      Register scratch,
172
      SaveFPRegsMode save_fp,
173
      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
174
      SmiCheck smi_check = INLINE_SMI_CHECK) {
175
    RecordWriteField(context,
176
                     offset + kHeapObjectTag,
177
                     value,
178
                     scratch,
179
                     save_fp,
180
                     remembered_set_action,
181
                     smi_check);
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,
192
      Register value,
193
      Register index,
194
      SaveFPRegsMode save_fp,
195
      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
196
      SmiCheck smi_check = INLINE_SMI_CHECK);
197

    
198
  // For page containing |object| mark region covering |address|
199
  // dirty. |object| is the object being stored into, |value| is the
200
  // object being stored. The address and value registers are clobbered by the
201
  // operation. RecordWrite filters out smis so it does not update the
202
  // write barrier if the value is a smi.
203
  void RecordWrite(
204
      Register object,
205
      Register address,
206
      Register value,
207
      SaveFPRegsMode save_fp,
208
      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
209
      SmiCheck smi_check = INLINE_SMI_CHECK);
210

    
211
  // For page containing |object| mark the region covering the object's map
212
  // dirty. |object| is the object being stored into, |map| is the Map object
213
  // that was stored.
214
  void RecordWriteForMap(
215
      Register object,
216
      Handle<Map> map,
217
      Register scratch1,
218
      Register scratch2,
219
      SaveFPRegsMode save_fp);
220

    
221
#ifdef ENABLE_DEBUGGER_SUPPORT
222
  // ---------------------------------------------------------------------------
223
  // Debugger Support
224

    
225
  void DebugBreak();
226
#endif
227

    
228
  // Generates function and stub prologue code.
229
  void Prologue(PrologueFrameMode frame_mode);
230

    
231
  // Enter specific kind of exit frame. Expects the number of
232
  // arguments in register eax and sets up the number of arguments in
233
  // register edi and the pointer to the first argument in register
234
  // esi.
235
  void EnterExitFrame(bool save_doubles);
236

    
237
  void EnterApiExitFrame(int argc);
238

    
239
  // Leave the current exit frame. Expects the return value in
240
  // register eax:edx (untouched) and the pointer to the first
241
  // argument in register esi.
242
  void LeaveExitFrame(bool save_doubles);
243

    
244
  // Leave the current exit frame. Expects the return value in
245
  // register eax (untouched).
246
  void LeaveApiExitFrame(bool restore_context);
247

    
248
  // Find the function context up the context chain.
249
  void LoadContext(Register dst, int context_chain_length);
250

    
251
  // Conditionally load the cached Array transitioned map of type
252
  // transitioned_kind from the native context if the map in register
253
  // map_in_out is the cached Array map in the native context of
254
  // expected_kind.
255
  void LoadTransitionedArrayMapConditional(
256
      ElementsKind expected_kind,
257
      ElementsKind transitioned_kind,
258
      Register map_in_out,
259
      Register scratch,
260
      Label* no_map_match);
261

    
262
  // Load the initial map for new Arrays from a JSFunction.
263
  void LoadInitialArrayMap(Register function_in,
264
                           Register scratch,
265
                           Register map_out,
266
                           bool can_have_holes);
267

    
268
  void LoadGlobalContext(Register global_context);
269

    
270
  // Load the global function with the given index.
271
  void LoadGlobalFunction(int index, Register function);
272

    
273
  // Load the initial map from the global function. The registers
274
  // function and map can be the same.
275
  void LoadGlobalFunctionInitialMap(Register function, Register map);
276

    
277
  // Push and pop the registers that can hold pointers.
278
  void PushSafepointRegisters() { pushad(); }
279
  void PopSafepointRegisters() { popad(); }
280
  // Store the value in register/immediate src in the safepoint
281
  // register stack slot for register dst.
282
  void StoreToSafepointRegisterSlot(Register dst, Register src);
283
  void StoreToSafepointRegisterSlot(Register dst, Immediate src);
284
  void LoadFromSafepointRegisterSlot(Register dst, Register src);
285

    
286
  void LoadHeapObject(Register result, Handle<HeapObject> object);
287
  void CmpHeapObject(Register reg, Handle<HeapObject> object);
288
  void PushHeapObject(Handle<HeapObject> object);
289

    
290
  void LoadObject(Register result, Handle<Object> object) {
291
    AllowDeferredHandleDereference heap_object_check;
292
    if (object->IsHeapObject()) {
293
      LoadHeapObject(result, Handle<HeapObject>::cast(object));
294
    } else {
295
      Set(result, Immediate(object));
296
    }
297
  }
298

    
299
  void CmpObject(Register reg, Handle<Object> object) {
300
    AllowDeferredHandleDereference heap_object_check;
301
    if (object->IsHeapObject()) {
302
      CmpHeapObject(reg, Handle<HeapObject>::cast(object));
303
    } else {
304
      cmp(reg, Immediate(object));
305
    }
306
  }
307

    
308
  // ---------------------------------------------------------------------------
309
  // JavaScript invokes
310

    
311
  // Set up call kind marking in ecx. The method takes ecx as an
312
  // explicit first parameter to make the code more readable at the
313
  // call sites.
314
  void SetCallKind(Register dst, CallKind kind);
315

    
316
  // Invoke the JavaScript function code by either calling or jumping.
317
  void InvokeCode(Register code,
318
                  const ParameterCount& expected,
319
                  const ParameterCount& actual,
320
                  InvokeFlag flag,
321
                  const CallWrapper& call_wrapper,
322
                  CallKind call_kind) {
323
    InvokeCode(Operand(code), expected, actual, flag, call_wrapper, call_kind);
324
  }
325

    
326
  void InvokeCode(const Operand& code,
327
                  const ParameterCount& expected,
328
                  const ParameterCount& actual,
329
                  InvokeFlag flag,
330
                  const CallWrapper& call_wrapper,
331
                  CallKind call_kind);
332

    
333
  void InvokeCode(Handle<Code> code,
334
                  const ParameterCount& expected,
335
                  const ParameterCount& actual,
336
                  RelocInfo::Mode rmode,
337
                  InvokeFlag flag,
338
                  const CallWrapper& call_wrapper,
339
                  CallKind call_kind);
340

    
341
  // Invoke the JavaScript function in the given register. Changes the
342
  // current context to the context in the function before invoking.
343
  void InvokeFunction(Register function,
344
                      const ParameterCount& actual,
345
                      InvokeFlag flag,
346
                      const CallWrapper& call_wrapper,
347
                      CallKind call_kind);
348

    
349
  void InvokeFunction(Handle<JSFunction> function,
350
                      const ParameterCount& expected,
351
                      const ParameterCount& actual,
352
                      InvokeFlag flag,
353
                      const CallWrapper& call_wrapper,
354
                      CallKind call_kind);
355

    
356
  // Invoke specified builtin JavaScript function. Adds an entry to
357
  // the unresolved list if the name does not resolve.
358
  void InvokeBuiltin(Builtins::JavaScript id,
359
                     InvokeFlag flag,
360
                     const CallWrapper& call_wrapper = NullCallWrapper());
361

    
362
  // Store the function for the given builtin in the target register.
363
  void GetBuiltinFunction(Register target, Builtins::JavaScript id);
364

    
365
  // Store the code object for the given builtin in the target register.
366
  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
367

    
368
  // Expression support
369
  void Set(Register dst, const Immediate& x);
370
  void Set(const Operand& dst, const Immediate& x);
371

    
372
  // cvtsi2sd instruction only writes to the low 64-bit of dst register, which
373
  // hinders register renaming and makes dependence chains longer. So we use
374
  // xorps to clear the dst register before cvtsi2sd to solve this issue.
375
  void Cvtsi2sd(XMMRegister dst, Register src) { Cvtsi2sd(dst, Operand(src)); }
376
  void Cvtsi2sd(XMMRegister dst, const Operand& src);
377

    
378
  // Support for constant splitting.
379
  bool IsUnsafeImmediate(const Immediate& x);
380
  void SafeSet(Register dst, const Immediate& x);
381
  void SafePush(const Immediate& x);
382

    
383
  // Compare object type for heap object.
384
  // Incoming register is heap_object and outgoing register is map.
385
  void CmpObjectType(Register heap_object, InstanceType type, Register map);
386

    
387
  // Compare instance type for map.
388
  void CmpInstanceType(Register map, InstanceType type);
389

    
390
  // Check if a map for a JSObject indicates that the object has fast elements.
391
  // Jump to the specified label if it does not.
392
  void CheckFastElements(Register map,
393
                         Label* fail,
394
                         Label::Distance distance = Label::kFar);
395

    
396
  // Check if a map for a JSObject indicates that the object can have both smi
397
  // and HeapObject elements.  Jump to the specified label if it does not.
398
  void CheckFastObjectElements(Register map,
399
                               Label* fail,
400
                               Label::Distance distance = Label::kFar);
401

    
402
  // Check if a map for a JSObject indicates that the object has fast smi only
403
  // elements.  Jump to the specified label if it does not.
404
  void CheckFastSmiElements(Register map,
405
                            Label* fail,
406
                            Label::Distance distance = Label::kFar);
407

    
408
  // Check to see if maybe_number can be stored as a double in
409
  // FastDoubleElements. If it can, store it at the index specified by key in
410
  // the FastDoubleElements array elements, otherwise jump to fail.
411
  void StoreNumberToDoubleElements(Register maybe_number,
412
                                   Register elements,
413
                                   Register key,
414
                                   Register scratch1,
415
                                   XMMRegister scratch2,
416
                                   Label* fail,
417
                                   bool specialize_for_processor,
418
                                   int offset = 0);
419

    
420
  // Compare an object's map with the specified map and its transitioned
421
  // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. FLAGS are set with
422
  // result of map compare. If multiple map compares are required, the compare
423
  // sequences branches to early_success.
424
  void CompareMap(Register obj,
425
                  Handle<Map> map,
426
                  Label* early_success);
427

    
428
  // Check if the map of an object is equal to a specified map and branch to
429
  // label if not. Skip the smi check if not required (object is known to be a
430
  // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
431
  // against maps that are ElementsKind transition maps of the specified map.
432
  void CheckMap(Register obj,
433
                Handle<Map> map,
434
                Label* fail,
435
                SmiCheckType smi_check_type);
436

    
437
  // Check if the map of an object is equal to a specified map and branch to a
438
  // specified target if equal. Skip the smi check if not required (object is
439
  // known to be a heap object)
440
  void DispatchMap(Register obj,
441
                   Register unused,
442
                   Handle<Map> map,
443
                   Handle<Code> success,
444
                   SmiCheckType smi_check_type);
445

    
446
  // Check if the object in register heap_object is a string. Afterwards the
447
  // register map contains the object map and the register instance_type
448
  // contains the instance_type. The registers map and instance_type can be the
449
  // same in which case it contains the instance type afterwards. Either of the
450
  // registers map and instance_type can be the same as heap_object.
451
  Condition IsObjectStringType(Register heap_object,
452
                               Register map,
453
                               Register instance_type);
454

    
455
  // Check if the object in register heap_object is a name. Afterwards the
456
  // register map contains the object map and the register instance_type
457
  // contains the instance_type. The registers map and instance_type can be the
458
  // same in which case it contains the instance type afterwards. Either of the
459
  // registers map and instance_type can be the same as heap_object.
460
  Condition IsObjectNameType(Register heap_object,
461
                             Register map,
462
                             Register instance_type);
463

    
464
  // Check if a heap object's type is in the JSObject range, not including
465
  // JSFunction.  The object's map will be loaded in the map register.
466
  // Any or all of the three registers may be the same.
467
  // The contents of the scratch register will always be overwritten.
468
  void IsObjectJSObjectType(Register heap_object,
469
                            Register map,
470
                            Register scratch,
471
                            Label* fail);
472

    
473
  // The contents of the scratch register will be overwritten.
474
  void IsInstanceJSObjectType(Register map, Register scratch, Label* fail);
475

    
476
  // FCmp is similar to integer cmp, but requires unsigned
477
  // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
478
  void FCmp();
479

    
480
  void ClampUint8(Register reg);
481

    
482
  void ClampDoubleToUint8(XMMRegister input_reg,
483
                          XMMRegister scratch_reg,
484
                          Register result_reg);
485

    
486
  void SlowTruncateToI(Register result_reg, Register input_reg,
487
      int offset = HeapNumber::kValueOffset - kHeapObjectTag);
488

    
489
  void TruncateHeapNumberToI(Register result_reg, Register input_reg);
490
  void TruncateDoubleToI(Register result_reg, XMMRegister input_reg);
491
  void TruncateX87TOSToI(Register result_reg);
492

    
493
  void DoubleToI(Register result_reg, XMMRegister input_reg,
494
      XMMRegister scratch, MinusZeroMode minus_zero_mode,
495
      Label* conversion_failed, Label::Distance dst = Label::kFar);
496
  void X87TOSToI(Register result_reg, MinusZeroMode minus_zero_mode,
497
      Label* conversion_failed, Label::Distance dst = Label::kFar);
498

    
499
  void TaggedToI(Register result_reg, Register input_reg, XMMRegister temp,
500
      MinusZeroMode minus_zero_mode, Label* lost_precision);
501

    
502
  // Smi tagging support.
503
  void SmiTag(Register reg) {
504
    STATIC_ASSERT(kSmiTag == 0);
505
    STATIC_ASSERT(kSmiTagSize == 1);
506
    add(reg, reg);
507
  }
508
  void SmiUntag(Register reg) {
509
    sar(reg, kSmiTagSize);
510
  }
511

    
512
  // Modifies the register even if it does not contain a Smi!
513
  void SmiUntag(Register reg, Label* is_smi) {
514
    STATIC_ASSERT(kSmiTagSize == 1);
515
    sar(reg, kSmiTagSize);
516
    STATIC_ASSERT(kSmiTag == 0);
517
    j(not_carry, is_smi);
518
  }
519

    
520
  void LoadUint32(XMMRegister dst, Register src, XMMRegister scratch);
521
  void LoadUint32NoSSE2(Register src);
522

    
523
  // Jump the register contains a smi.
524
  inline void JumpIfSmi(Register value,
525
                        Label* smi_label,
526
                        Label::Distance distance = Label::kFar) {
527
    test(value, Immediate(kSmiTagMask));
528
    j(zero, smi_label, distance);
529
  }
530
  // Jump if the operand is a smi.
531
  inline void JumpIfSmi(Operand value,
532
                        Label* smi_label,
533
                        Label::Distance distance = Label::kFar) {
534
    test(value, Immediate(kSmiTagMask));
535
    j(zero, smi_label, distance);
536
  }
537
  // Jump if register contain a non-smi.
538
  inline void JumpIfNotSmi(Register value,
539
                           Label* not_smi_label,
540
                           Label::Distance distance = Label::kFar) {
541
    test(value, Immediate(kSmiTagMask));
542
    j(not_zero, not_smi_label, distance);
543
  }
544

    
545
  void LoadInstanceDescriptors(Register map, Register descriptors);
546
  void EnumLength(Register dst, Register map);
547
  void NumberOfOwnDescriptors(Register dst, Register map);
548

    
549
  template<typename Field>
550
  void DecodeField(Register reg) {
551
    static const int shift = Field::kShift;
552
    static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize;
553
    sar(reg, shift);
554
    and_(reg, Immediate(mask));
555
  }
556
  void LoadPowerOf2(XMMRegister dst, Register scratch, int power);
557

    
558
  // Abort execution if argument is not a number, enabled via --debug-code.
559
  void AssertNumber(Register object);
560

    
561
  // Abort execution if argument is not a smi, enabled via --debug-code.
562
  void AssertSmi(Register object);
563

    
564
  // Abort execution if argument is a smi, enabled via --debug-code.
565
  void AssertNotSmi(Register object);
566

    
567
  // Abort execution if argument is not a string, enabled via --debug-code.
568
  void AssertString(Register object);
569

    
570
  // Abort execution if argument is not a name, enabled via --debug-code.
571
  void AssertName(Register object);
572

    
573
  // ---------------------------------------------------------------------------
574
  // Exception handling
575

    
576
  // Push a new try handler and link it into try handler chain.
577
  void PushTryHandler(StackHandler::Kind kind, int handler_index);
578

    
579
  // Unlink the stack handler on top of the stack from the try handler chain.
580
  void PopTryHandler();
581

    
582
  // Throw to the top handler in the try hander chain.
583
  void Throw(Register value);
584

    
585
  // Throw past all JS frames to the top JS entry frame.
586
  void ThrowUncatchable(Register value);
587

    
588
  // ---------------------------------------------------------------------------
589
  // Inline caching support
590

    
591
  // Generate code for checking access rights - used for security checks
592
  // on access to global objects across environments. The holder register
593
  // is left untouched, but the scratch register is clobbered.
594
  void CheckAccessGlobalProxy(Register holder_reg,
595
                              Register scratch1,
596
                              Register scratch2,
597
                              Label* miss);
598

    
599
  void GetNumberHash(Register r0, Register scratch);
600

    
601
  void LoadFromNumberDictionary(Label* miss,
602
                                Register elements,
603
                                Register key,
604
                                Register r0,
605
                                Register r1,
606
                                Register r2,
607
                                Register result);
608

    
609

    
610
  // ---------------------------------------------------------------------------
611
  // Allocation support
612

    
613
  // Allocate an object in new space or old pointer space. If the given space
614
  // is exhausted control continues at the gc_required label. The allocated
615
  // object is returned in result and end of the new object is returned in
616
  // result_end. The register scratch can be passed as no_reg in which case
617
  // an additional object reference will be added to the reloc info. The
618
  // returned pointers in result and result_end have not yet been tagged as
619
  // heap objects. If result_contains_top_on_entry is true the content of
620
  // result is known to be the allocation top on entry (could be result_end
621
  // from a previous call). If result_contains_top_on_entry is true scratch
622
  // should be no_reg as it is never used.
623
  void Allocate(int object_size,
624
                Register result,
625
                Register result_end,
626
                Register scratch,
627
                Label* gc_required,
628
                AllocationFlags flags);
629

    
630
  void Allocate(int header_size,
631
                ScaleFactor element_size,
632
                Register element_count,
633
                RegisterValueType element_count_type,
634
                Register result,
635
                Register result_end,
636
                Register scratch,
637
                Label* gc_required,
638
                AllocationFlags flags);
639

    
640
  void Allocate(Register object_size,
641
                Register result,
642
                Register result_end,
643
                Register scratch,
644
                Label* gc_required,
645
                AllocationFlags flags);
646

    
647
  // Undo allocation in new space. The object passed and objects allocated after
648
  // it will no longer be allocated. Make sure that no pointers are left to the
649
  // object(s) no longer allocated as they would be invalid when allocation is
650
  // un-done.
651
  void UndoAllocationInNewSpace(Register object);
652

    
653
  // Allocate a heap number in new space with undefined value. The
654
  // register scratch2 can be passed as no_reg; the others must be
655
  // valid registers. Returns tagged pointer in result register, or
656
  // jumps to gc_required if new space is full.
657
  void AllocateHeapNumber(Register result,
658
                          Register scratch1,
659
                          Register scratch2,
660
                          Label* gc_required);
661

    
662
  // Allocate a sequential string. All the header fields of the string object
663
  // are initialized.
664
  void AllocateTwoByteString(Register result,
665
                             Register length,
666
                             Register scratch1,
667
                             Register scratch2,
668
                             Register scratch3,
669
                             Label* gc_required);
670
  void AllocateAsciiString(Register result,
671
                           Register length,
672
                           Register scratch1,
673
                           Register scratch2,
674
                           Register scratch3,
675
                           Label* gc_required);
676
  void AllocateAsciiString(Register result,
677
                           int length,
678
                           Register scratch1,
679
                           Register scratch2,
680
                           Label* gc_required);
681

    
682
  // Allocate a raw cons string object. Only the map field of the result is
683
  // initialized.
684
  void AllocateTwoByteConsString(Register result,
685
                          Register scratch1,
686
                          Register scratch2,
687
                          Label* gc_required);
688
  void AllocateAsciiConsString(Register result,
689
                               Register scratch1,
690
                               Register scratch2,
691
                               Label* gc_required);
692

    
693
  // Allocate a raw sliced string object. Only the map field of the result is
694
  // initialized.
695
  void AllocateTwoByteSlicedString(Register result,
696
                            Register scratch1,
697
                            Register scratch2,
698
                            Label* gc_required);
699
  void AllocateAsciiSlicedString(Register result,
700
                                 Register scratch1,
701
                                 Register scratch2,
702
                                 Label* gc_required);
703

    
704
  // Copy memory, byte-by-byte, from source to destination.  Not optimized for
705
  // long or aligned copies.
706
  // The contents of index and scratch are destroyed.
707
  void CopyBytes(Register source,
708
                 Register destination,
709
                 Register length,
710
                 Register scratch);
711

    
712
  // Initialize fields with filler values.  Fields starting at |start_offset|
713
  // not including end_offset are overwritten with the value in |filler|.  At
714
  // the end the loop, |start_offset| takes the value of |end_offset|.
715
  void InitializeFieldsWithFiller(Register start_offset,
716
                                  Register end_offset,
717
                                  Register filler);
718

    
719
  // ---------------------------------------------------------------------------
720
  // Support functions.
721

    
722
  // Check a boolean-bit of a Smi field.
723
  void BooleanBitTest(Register object, int field_offset, int bit_index);
724

    
725
  // Check if result is zero and op is negative.
726
  void NegativeZeroTest(Register result, Register op, Label* then_label);
727

    
728
  // Check if result is zero and any of op1 and op2 are negative.
729
  // Register scratch is destroyed, and it must be different from op2.
730
  void NegativeZeroTest(Register result, Register op1, Register op2,
731
                        Register scratch, Label* then_label);
732

    
733
  // Try to get function prototype of a function and puts the value in
734
  // the result register. Checks that the function really is a
735
  // function and jumps to the miss label if the fast checks fail. The
736
  // function register will be untouched; the other registers may be
737
  // clobbered.
738
  void TryGetFunctionPrototype(Register function,
739
                               Register result,
740
                               Register scratch,
741
                               Label* miss,
742
                               bool miss_on_bound_function = false);
743

    
744
  // Generates code for reporting that an illegal operation has
745
  // occurred.
746
  void IllegalOperation(int num_arguments);
747

    
748
  // Picks out an array index from the hash field.
749
  // Register use:
750
  //   hash - holds the index's hash. Clobbered.
751
  //   index - holds the overwritten index on exit.
752
  void IndexFromHash(Register hash, Register index);
753

    
754
  // ---------------------------------------------------------------------------
755
  // Runtime calls
756

    
757
  // Call a code stub.  Generate the code if necessary.
758
  void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
759

    
760
  // Tail call a code stub (jump).  Generate the code if necessary.
761
  void TailCallStub(CodeStub* stub);
762

    
763
  // Return from a code stub after popping its arguments.
764
  void StubReturn(int argc);
765

    
766
  // Call a runtime routine.
767
  void CallRuntime(const Runtime::Function* f,
768
                   int num_arguments,
769
                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
770
  void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
771
    const Runtime::Function* function = Runtime::FunctionForId(id);
772
    CallRuntime(function, function->nargs, kSaveFPRegs);
773
  }
774

    
775
  // Convenience function: Same as above, but takes the fid instead.
776
  void CallRuntime(Runtime::FunctionId id, int num_arguments) {
777
    CallRuntime(Runtime::FunctionForId(id), num_arguments);
778
  }
779

    
780
  // Convenience function: call an external reference.
781
  void CallExternalReference(ExternalReference ref, int num_arguments);
782

    
783
  // Tail call of a runtime routine (jump).
784
  // Like JumpToExternalReference, but also takes care of passing the number
785
  // of parameters.
786
  void TailCallExternalReference(const ExternalReference& ext,
787
                                 int num_arguments,
788
                                 int result_size);
789

    
790
  // Convenience function: tail call a runtime routine (jump).
791
  void TailCallRuntime(Runtime::FunctionId fid,
792
                       int num_arguments,
793
                       int result_size);
794

    
795
  // Before calling a C-function from generated code, align arguments on stack.
796
  // After aligning the frame, arguments must be stored in esp[0], esp[4],
797
  // etc., not pushed. The argument count assumes all arguments are word sized.
798
  // Some compilers/platforms require the stack to be aligned when calling
799
  // C++ code.
800
  // Needs a scratch register to do some arithmetic. This register will be
801
  // trashed.
802
  void PrepareCallCFunction(int num_arguments, Register scratch);
803

    
804
  // Calls a C function and cleans up the space for arguments allocated
805
  // by PrepareCallCFunction. The called function is not allowed to trigger a
806
  // garbage collection, since that might move the code and invalidate the
807
  // return address (unless this is somehow accounted for by the called
808
  // function).
809
  void CallCFunction(ExternalReference function, int num_arguments);
810
  void CallCFunction(Register function, int num_arguments);
811

    
812
  // Prepares stack to put arguments (aligns and so on). Reserves
813
  // space for return value if needed (assumes the return value is a handle).
814
  // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1)
815
  // etc. Saves context (esi). If space was reserved for return value then
816
  // stores the pointer to the reserved slot into esi.
817
  void PrepareCallApiFunction(int argc);
818

    
819
  // Calls an API function.  Allocates HandleScope, extracts returned value
820
  // from handle and propagates exceptions.  Clobbers ebx, edi and
821
  // caller-save registers.  Restores context.  On return removes
822
  // stack_space * kPointerSize (GCed).
823
  void CallApiFunctionAndReturn(Address function_address,
824
                                Address thunk_address,
825
                                Operand thunk_last_arg,
826
                                int stack_space,
827
                                Operand return_value_operand,
828
                                Operand* context_restore_operand);
829

    
830
  // Jump to a runtime routine.
831
  void JumpToExternalReference(const ExternalReference& ext);
832

    
833
  // ---------------------------------------------------------------------------
834
  // Utilities
835

    
836
  void Ret();
837

    
838
  // Return and drop arguments from stack, where the number of arguments
839
  // may be bigger than 2^16 - 1.  Requires a scratch register.
840
  void Ret(int bytes_dropped, Register scratch);
841

    
842
  // Emit code to discard a non-negative number of pointer-sized elements
843
  // from the stack, clobbering only the esp register.
844
  void Drop(int element_count);
845

    
846
  void Call(Label* target) { call(target); }
847
  void Push(Register src) { push(src); }
848
  void Pop(Register dst) { pop(dst); }
849

    
850
  // Emit call to the code we are currently generating.
851
  void CallSelf() {
852
    Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
853
    call(self, RelocInfo::CODE_TARGET);
854
  }
855

    
856
  // Move if the registers are not identical.
857
  void Move(Register target, Register source);
858

    
859
  // Push a handle value.
860
  void Push(Handle<Object> handle) { push(Immediate(handle)); }
861
  void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
862

    
863
  Handle<Object> CodeObject() {
864
    ASSERT(!code_object_.is_null());
865
    return code_object_;
866
  }
867

    
868
  // Insert code to verify that the x87 stack has the specified depth (0-7)
869
  void VerifyX87StackDepth(uint32_t depth);
870

    
871
  // ---------------------------------------------------------------------------
872
  // StatsCounter support
873

    
874
  void SetCounter(StatsCounter* counter, int value);
875
  void IncrementCounter(StatsCounter* counter, int value);
876
  void DecrementCounter(StatsCounter* counter, int value);
877
  void IncrementCounter(Condition cc, StatsCounter* counter, int value);
878
  void DecrementCounter(Condition cc, StatsCounter* counter, int value);
879

    
880

    
881
  // ---------------------------------------------------------------------------
882
  // Debugging
883

    
884
  // Calls Abort(msg) if the condition cc is not satisfied.
885
  // Use --debug_code to enable.
886
  void Assert(Condition cc, BailoutReason reason);
887

    
888
  void AssertFastElements(Register elements);
889

    
890
  // Like Assert(), but always enabled.
891
  void Check(Condition cc, BailoutReason reason);
892

    
893
  // Print a message to stdout and abort execution.
894
  void Abort(BailoutReason reason);
895

    
896
  // Check that the stack is aligned.
897
  void CheckStackAlignment();
898

    
899
  // Verify restrictions about code generated in stubs.
900
  void set_generating_stub(bool value) { generating_stub_ = value; }
901
  bool generating_stub() { return generating_stub_; }
902
  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
903
  bool allow_stub_calls() { return allow_stub_calls_; }
904
  void set_has_frame(bool value) { has_frame_ = value; }
905
  bool has_frame() { return has_frame_; }
906
  inline bool AllowThisStubCall(CodeStub* stub);
907

    
908
  // ---------------------------------------------------------------------------
909
  // String utilities.
910

    
911
  // Generate code to do a lookup in the number string cache. If the number in
912
  // the register object is found in the cache the generated code falls through
913
  // with the result in the result register. The object and the result register
914
  // can be the same. If the number is not found in the cache the code jumps to
915
  // the label not_found with only the content of register object unchanged.
916
  void LookupNumberStringCache(Register object,
917
                               Register result,
918
                               Register scratch1,
919
                               Register scratch2,
920
                               Label* not_found);
921

    
922
  // Check whether the instance type represents a flat ASCII string. Jump to the
923
  // label if not. If the instance type can be scratched specify same register
924
  // for both instance type and scratch.
925
  void JumpIfInstanceTypeIsNotSequentialAscii(Register instance_type,
926
                                              Register scratch,
927
                                              Label* on_not_flat_ascii_string);
928

    
929
  // Checks if both objects are sequential ASCII strings, and jumps to label
930
  // if either is not.
931
  void JumpIfNotBothSequentialAsciiStrings(Register object1,
932
                                           Register object2,
933
                                           Register scratch1,
934
                                           Register scratch2,
935
                                           Label* on_not_flat_ascii_strings);
936

    
937
  // Checks if the given register or operand is a unique name
938
  void JumpIfNotUniqueName(Register reg, Label* not_unique_name,
939
                           Label::Distance distance = Label::kFar) {
940
    JumpIfNotUniqueName(Operand(reg), not_unique_name, distance);
941
  }
942

    
943
  void JumpIfNotUniqueName(Operand operand, Label* not_unique_name,
944
                           Label::Distance distance = Label::kFar);
945

    
946
  static int SafepointRegisterStackIndex(Register reg) {
947
    return SafepointRegisterStackIndex(reg.code());
948
  }
949

    
950
  // Activation support.
951
  void EnterFrame(StackFrame::Type type);
952
  void LeaveFrame(StackFrame::Type type);
953

    
954
  // Expects object in eax and returns map with validated enum cache
955
  // in eax.  Assumes that any other register can be used as a scratch.
956
  void CheckEnumCache(Label* call_runtime);
957

    
958
  // AllocationMemento support. Arrays may have an associated
959
  // AllocationMemento object that can be checked for in order to pretransition
960
  // to another type.
961
  // On entry, receiver_reg should point to the array object.
962
  // scratch_reg gets clobbered.
963
  // If allocation info is present, conditional code is set to equal.
964
  void TestJSArrayForAllocationMemento(Register receiver_reg,
965
                                       Register scratch_reg,
966
                                       Label* no_memento_found);
967

    
968
  void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
969
                                         Register scratch_reg,
970
                                         Label* memento_found) {
971
    Label no_memento_found;
972
    TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
973
                                    &no_memento_found);
974
    j(equal, memento_found);
975
    bind(&no_memento_found);
976
  }
977

    
978
 private:
979
  bool generating_stub_;
980
  bool allow_stub_calls_;
981
  bool has_frame_;
982
  // This handle will be patched with the code object on installation.
983
  Handle<Object> code_object_;
984

    
985
  // Helper functions for generating invokes.
986
  void InvokePrologue(const ParameterCount& expected,
987
                      const ParameterCount& actual,
988
                      Handle<Code> code_constant,
989
                      const Operand& code_operand,
990
                      Label* done,
991
                      bool* definitely_mismatches,
992
                      InvokeFlag flag,
993
                      Label::Distance done_distance,
994
                      const CallWrapper& call_wrapper = NullCallWrapper(),
995
                      CallKind call_kind = CALL_AS_METHOD);
996

    
997
  void EnterExitFramePrologue();
998
  void EnterExitFrameEpilogue(int argc, bool save_doubles);
999

    
1000
  void LeaveExitFrameEpilogue(bool restore_context);
1001

    
1002
  // Allocation support helpers.
1003
  void LoadAllocationTopHelper(Register result,
1004
                               Register scratch,
1005
                               AllocationFlags flags);
1006

    
1007
  void UpdateAllocationTopHelper(Register result_end,
1008
                                 Register scratch,
1009
                                 AllocationFlags flags);
1010

    
1011
  // Helper for PopHandleScope.  Allowed to perform a GC and returns
1012
  // NULL if gc_allowed.  Does not perform a GC if !gc_allowed, and
1013
  // possibly returns a failure object indicating an allocation failure.
1014
  MUST_USE_RESULT MaybeObject* PopHandleScopeHelper(Register saved,
1015
                                                    Register scratch,
1016
                                                    bool gc_allowed);
1017

    
1018
  // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
1019
  void InNewSpace(Register object,
1020
                  Register scratch,
1021
                  Condition cc,
1022
                  Label* condition_met,
1023
                  Label::Distance condition_met_distance = Label::kFar);
1024

    
1025
  // Helper for finding the mark bits for an address.  Afterwards, the
1026
  // bitmap register points at the word with the mark bits and the mask
1027
  // the position of the first bit.  Uses ecx as scratch and leaves addr_reg
1028
  // unchanged.
1029
  inline void GetMarkBits(Register addr_reg,
1030
                          Register bitmap_reg,
1031
                          Register mask_reg);
1032

    
1033
  // Helper for throwing exceptions.  Compute a handler address and jump to
1034
  // it.  See the implementation for register usage.
1035
  void JumpToHandlerEntry();
1036

    
1037
  // Compute memory operands for safepoint stack slots.
1038
  Operand SafepointRegisterSlot(Register reg);
1039
  static int SafepointRegisterStackIndex(int reg_code);
1040

    
1041
  // Needs access to SafepointRegisterStackIndex for compiled frame
1042
  // traversal.
1043
  friend class StandardFrame;
1044
};
1045

    
1046

    
1047
// The code patcher is used to patch (typically) small parts of code e.g. for
1048
// debugging and other types of instrumentation. When using the code patcher
1049
// the exact number of bytes specified must be emitted. Is not legal to emit
1050
// relocation information. If any of these constraints are violated it causes
1051
// an assertion.
1052
class CodePatcher {
1053
 public:
1054
  CodePatcher(byte* address, int size);
1055
  virtual ~CodePatcher();
1056

    
1057
  // Macro assembler to emit code.
1058
  MacroAssembler* masm() { return &masm_; }
1059

    
1060
 private:
1061
  byte* address_;  // The address of the code being patched.
1062
  int size_;  // Number of bytes of the expected patch size.
1063
  MacroAssembler masm_;  // Macro assembler used to generate the code.
1064
};
1065

    
1066

    
1067
// -----------------------------------------------------------------------------
1068
// Static helper functions.
1069

    
1070
// Generate an Operand for loading a field from an object.
1071
inline Operand FieldOperand(Register object, int offset) {
1072
  return Operand(object, offset - kHeapObjectTag);
1073
}
1074

    
1075

    
1076
// Generate an Operand for loading an indexed field from an object.
1077
inline Operand FieldOperand(Register object,
1078
                            Register index,
1079
                            ScaleFactor scale,
1080
                            int offset) {
1081
  return Operand(object, index, scale, offset - kHeapObjectTag);
1082
}
1083

    
1084

    
1085
inline Operand ContextOperand(Register context, int index) {
1086
  return Operand(context, Context::SlotOffset(index));
1087
}
1088

    
1089

    
1090
inline Operand GlobalObjectOperand() {
1091
  return ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX);
1092
}
1093

    
1094

    
1095
// Generates an Operand for saving parameters after PrepareCallApiFunction.
1096
Operand ApiParameterOperand(int index);
1097

    
1098

    
1099
#ifdef GENERATED_CODE_COVERAGE
1100
extern void LogGeneratedCodeCoverage(const char* file_line);
1101
#define CODE_COVERAGE_STRINGIFY(x) #x
1102
#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1103
#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1104
#define ACCESS_MASM(masm) {                                               \
1105
    byte* ia32_coverage_function =                                        \
1106
        reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
1107
    masm->pushfd();                                                       \
1108
    masm->pushad();                                                       \
1109
    masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__)));         \
1110
    masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY);         \
1111
    masm->pop(eax);                                                       \
1112
    masm->popad();                                                        \
1113
    masm->popfd();                                                        \
1114
  }                                                                       \
1115
  masm->
1116
#else
1117
#define ACCESS_MASM(masm) masm->
1118
#endif
1119

    
1120

    
1121
} }  // namespace v8::internal
1122

    
1123
#endif  // V8_IA32_MACRO_ASSEMBLER_IA32_H_