macro-assembler-arm.h revision 0d5e116f6aee03185f237311a943491bb079a768
1// Copyright 2006-2009 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_ARM_MACRO_ASSEMBLER_ARM_H_
29#define V8_ARM_MACRO_ASSEMBLER_ARM_H_
30
31#include "assembler.h"
32
33namespace v8 {
34namespace internal {
35
36// ----------------------------------------------------------------------------
37// Static helper functions
38
39// Generate a MemOperand for loading a field from an object.
40static inline MemOperand FieldMemOperand(Register object, int offset) {
41  return MemOperand(object, offset - kHeapObjectTag);
42}
43
44
45// Give alias names to registers
46const Register cp = { 8 };  // JavaScript context pointer
47const Register roots = { 10 };  // Roots array pointer.
48
49enum InvokeJSFlags {
50  CALL_JS,
51  JUMP_JS
52};
53
54
55// Flags used for the AllocateInNewSpace functions.
56enum AllocationFlags {
57  // No special flags.
58  NO_ALLOCATION_FLAGS = 0,
59  // Return the pointer to the allocated already tagged as a heap object.
60  TAG_OBJECT = 1 << 0,
61  // The content of the result register already contains the allocation top in
62  // new space.
63  RESULT_CONTAINS_TOP = 1 << 1,
64  // Specify that the requested size of the space to allocate is specified in
65  // words instead of bytes.
66  SIZE_IN_WORDS = 1 << 2
67};
68
69
70// Flags used for the ObjectToDoubleVFPRegister function.
71enum ObjectToDoubleFlags {
72  // No special flags.
73  NO_OBJECT_TO_DOUBLE_FLAGS = 0,
74  // Object is known to be a non smi.
75  OBJECT_NOT_SMI = 1 << 0,
76  // Don't load NaNs or infinities, branch to the non number case instead.
77  AVOID_NANS_AND_INFINITIES = 1 << 1
78};
79
80
81// MacroAssembler implements a collection of frequently used macros.
82class MacroAssembler: public Assembler {
83 public:
84  MacroAssembler(void* buffer, int size);
85
86  // Jump, Call, and Ret pseudo instructions implementing inter-working.
87  void Jump(Register target, Condition cond = al);
88  void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
89  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
90  void Call(Register target, Condition cond = al);
91  void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
92  void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
93  void Ret(Condition cond = al);
94
95  // Emit code to discard a non-negative number of pointer-sized elements
96  // from the stack, clobbering only the sp register.
97  void Drop(int count, Condition cond = al);
98
99
100  // Swap two registers.  If the scratch register is omitted then a slightly
101  // less efficient form using xor instead of mov is emitted.
102  void Swap(Register reg1,
103            Register reg2,
104            Register scratch = no_reg,
105            Condition cond = al);
106
107
108  void And(Register dst, Register src1, const Operand& src2,
109           Condition cond = al);
110  void Ubfx(Register dst, Register src, int lsb, int width,
111            Condition cond = al);
112  void Sbfx(Register dst, Register src, int lsb, int width,
113            Condition cond = al);
114  void Bfc(Register dst, int lsb, int width, Condition cond = al);
115  void Usat(Register dst, int satpos, const Operand& src,
116            Condition cond = al);
117
118  void Call(Label* target);
119  void Move(Register dst, Handle<Object> value);
120  // May do nothing if the registers are identical.
121  void Move(Register dst, Register src);
122  // Jumps to the label at the index given by the Smi in "index".
123  void SmiJumpTable(Register index, Vector<Label*> targets);
124  // Load an object from the root table.
125  void LoadRoot(Register destination,
126                Heap::RootListIndex index,
127                Condition cond = al);
128  // Store an object to the root table.
129  void StoreRoot(Register source,
130                 Heap::RootListIndex index,
131                 Condition cond = al);
132
133
134  // Check if object is in new space.
135  // scratch can be object itself, but it will be clobbered.
136  void InNewSpace(Register object,
137                  Register scratch,
138                  Condition cc,  // eq for new space, ne otherwise
139                  Label* branch);
140
141
142  // For the page containing |object| mark the region covering [address]
143  // dirty. The object address must be in the first 8K of an allocated page.
144  void RecordWriteHelper(Register object,
145                         Register address,
146                         Register scratch);
147
148  // For the page containing |object| mark the region covering
149  // [object+offset] dirty. The object address must be in the first 8K
150  // of an allocated page.  The 'scratch' registers are used in the
151  // implementation and all 3 registers are clobbered by the
152  // operation, as well as the ip register. RecordWrite updates the
153  // write barrier even when storing smis.
154  void RecordWrite(Register object,
155                   Operand offset,
156                   Register scratch0,
157                   Register scratch1);
158
159  // For the page containing |object| mark the region covering
160  // [address] dirty. The object address must be in the first 8K of an
161  // allocated page.  All 3 registers are clobbered by the operation,
162  // as well as the ip register. RecordWrite updates the write barrier
163  // even when storing smis.
164  void RecordWrite(Register object,
165                   Register address,
166                   Register scratch);
167
168  // Push two registers.  Pushes leftmost register first (to highest address).
169  void Push(Register src1, Register src2, Condition cond = al) {
170    ASSERT(!src1.is(src2));
171    if (src1.code() > src2.code()) {
172      stm(db_w, sp, src1.bit() | src2.bit(), cond);
173    } else {
174      str(src1, MemOperand(sp, 4, NegPreIndex), cond);
175      str(src2, MemOperand(sp, 4, NegPreIndex), cond);
176    }
177  }
178
179  // Push three registers.  Pushes leftmost register first (to highest address).
180  void Push(Register src1, Register src2, Register src3, Condition cond = al) {
181    ASSERT(!src1.is(src2));
182    ASSERT(!src2.is(src3));
183    ASSERT(!src1.is(src3));
184    if (src1.code() > src2.code()) {
185      if (src2.code() > src3.code()) {
186        stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
187      } else {
188        stm(db_w, sp, src1.bit() | src2.bit(), cond);
189        str(src3, MemOperand(sp, 4, NegPreIndex), cond);
190      }
191    } else {
192      str(src1, MemOperand(sp, 4, NegPreIndex), cond);
193      Push(src2, src3, cond);
194    }
195  }
196
197  // Push four registers.  Pushes leftmost register first (to highest address).
198  void Push(Register src1, Register src2,
199            Register src3, Register src4, Condition cond = al) {
200    ASSERT(!src1.is(src2));
201    ASSERT(!src2.is(src3));
202    ASSERT(!src1.is(src3));
203    ASSERT(!src1.is(src4));
204    ASSERT(!src2.is(src4));
205    ASSERT(!src3.is(src4));
206    if (src1.code() > src2.code()) {
207      if (src2.code() > src3.code()) {
208        if (src3.code() > src4.code()) {
209          stm(db_w,
210              sp,
211              src1.bit() | src2.bit() | src3.bit() | src4.bit(),
212              cond);
213        } else {
214          stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
215          str(src4, MemOperand(sp, 4, NegPreIndex), cond);
216        }
217      } else {
218        stm(db_w, sp, src1.bit() | src2.bit(), cond);
219        Push(src3, src4, cond);
220      }
221    } else {
222      str(src1, MemOperand(sp, 4, NegPreIndex), cond);
223      Push(src2, src3, src4, cond);
224    }
225  }
226
227  // Load two consecutive registers with two consecutive memory locations.
228  void Ldrd(Register dst1,
229            Register dst2,
230            const MemOperand& src,
231            Condition cond = al);
232
233  // Store two consecutive registers to two consecutive memory locations.
234  void Strd(Register src1,
235            Register src2,
236            const MemOperand& dst,
237            Condition cond = al);
238
239  // ---------------------------------------------------------------------------
240  // Stack limit support
241
242  void StackLimitCheck(Label* on_stack_limit_hit);
243
244  // ---------------------------------------------------------------------------
245  // Activation frames
246
247  void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
248  void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
249
250  void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
251  void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
252
253  // Enter exit frame.
254  // Expects the number of arguments in register r0 and
255  // the builtin function to call in register r1. Exits with argc in
256  // r4, argv in r6, and and the builtin function to call in r5.
257  void EnterExitFrame();
258
259  // Leave the current exit frame. Expects the return value in r0.
260  void LeaveExitFrame();
261
262  // Get the actual activation frame alignment for target environment.
263  static int ActivationFrameAlignment();
264
265  void LoadContext(Register dst, int context_chain_length);
266
267  // ---------------------------------------------------------------------------
268  // JavaScript invokes
269
270  // Invoke the JavaScript function code by either calling or jumping.
271  void InvokeCode(Register code,
272                  const ParameterCount& expected,
273                  const ParameterCount& actual,
274                  InvokeFlag flag);
275
276  void InvokeCode(Handle<Code> code,
277                  const ParameterCount& expected,
278                  const ParameterCount& actual,
279                  RelocInfo::Mode rmode,
280                  InvokeFlag flag);
281
282  // Invoke the JavaScript function in the given register. Changes the
283  // current context to the context in the function before invoking.
284  void InvokeFunction(Register function,
285                      const ParameterCount& actual,
286                      InvokeFlag flag);
287
288  void InvokeFunction(JSFunction* function,
289                      const ParameterCount& actual,
290                      InvokeFlag flag);
291
292
293#ifdef ENABLE_DEBUGGER_SUPPORT
294  // ---------------------------------------------------------------------------
295  // Debugger Support
296
297  void DebugBreak();
298#endif
299
300  // ---------------------------------------------------------------------------
301  // Exception handling
302
303  // Push a new try handler and link into try handler chain.
304  // The return address must be passed in register lr.
305  // On exit, r0 contains TOS (code slot).
306  void PushTryHandler(CodeLocation try_location, HandlerType type);
307
308  // Unlink the stack handler on top of the stack from the try handler chain.
309  // Must preserve the result register.
310  void PopTryHandler();
311
312  // ---------------------------------------------------------------------------
313  // Inline caching support
314
315  // Generate code for checking access rights - used for security checks
316  // on access to global objects across environments. The holder register
317  // is left untouched, whereas both scratch registers are clobbered.
318  void CheckAccessGlobalProxy(Register holder_reg,
319                              Register scratch,
320                              Label* miss);
321
322
323  // ---------------------------------------------------------------------------
324  // Allocation support
325
326  // Allocate an object in new space. The object_size is specified in words (not
327  // bytes). If the new space is exhausted control continues at the gc_required
328  // label. The allocated object is returned in result. If the flag
329  // tag_allocated_object is true the result is tagged as as a heap object. All
330  // registers are clobbered also when control continues at the gc_required
331  // label.
332  void AllocateInNewSpace(int object_size,
333                          Register result,
334                          Register scratch1,
335                          Register scratch2,
336                          Label* gc_required,
337                          AllocationFlags flags);
338  void AllocateInNewSpace(Register object_size,
339                          Register result,
340                          Register scratch1,
341                          Register scratch2,
342                          Label* gc_required,
343                          AllocationFlags flags);
344
345  // Undo allocation in new space. The object passed and objects allocated after
346  // it will no longer be allocated. The caller must make sure that no pointers
347  // are left to the object(s) no longer allocated as they would be invalid when
348  // allocation is undone.
349  void UndoAllocationInNewSpace(Register object, Register scratch);
350
351
352  void AllocateTwoByteString(Register result,
353                             Register length,
354                             Register scratch1,
355                             Register scratch2,
356                             Register scratch3,
357                             Label* gc_required);
358  void AllocateAsciiString(Register result,
359                           Register length,
360                           Register scratch1,
361                           Register scratch2,
362                           Register scratch3,
363                           Label* gc_required);
364  void AllocateTwoByteConsString(Register result,
365                                 Register length,
366                                 Register scratch1,
367                                 Register scratch2,
368                                 Label* gc_required);
369  void AllocateAsciiConsString(Register result,
370                               Register length,
371                               Register scratch1,
372                               Register scratch2,
373                               Label* gc_required);
374
375  // Allocates a heap number or jumps to the gc_required label if the young
376  // space is full and a scavenge is needed. All registers are clobbered also
377  // when control continues at the gc_required label.
378  void AllocateHeapNumber(Register result,
379                          Register scratch1,
380                          Register scratch2,
381                          Register heap_number_map,
382                          Label* gc_required);
383  void AllocateHeapNumberWithValue(Register result,
384                                   DwVfpRegister value,
385                                   Register scratch1,
386                                   Register scratch2,
387                                   Register heap_number_map,
388                                   Label* gc_required);
389
390  // Copies a fixed number of fields of heap objects from src to dst.
391  void CopyFields(Register dst, Register src, RegList temps, int field_count);
392
393  // ---------------------------------------------------------------------------
394  // Support functions.
395
396  // Try to get function prototype of a function and puts the value in
397  // the result register. Checks that the function really is a
398  // function and jumps to the miss label if the fast checks fail. The
399  // function register will be untouched; the other registers may be
400  // clobbered.
401  void TryGetFunctionPrototype(Register function,
402                               Register result,
403                               Register scratch,
404                               Label* miss);
405
406  // Compare object type for heap object.  heap_object contains a non-Smi
407  // whose object type should be compared with the given type.  This both
408  // sets the flags and leaves the object type in the type_reg register.
409  // It leaves the map in the map register (unless the type_reg and map register
410  // are the same register).  It leaves the heap object in the heap_object
411  // register unless the heap_object register is the same register as one of the
412  // other registers.
413  void CompareObjectType(Register heap_object,
414                         Register map,
415                         Register type_reg,
416                         InstanceType type);
417
418  // Compare instance type in a map.  map contains a valid map object whose
419  // object type should be compared with the given type.  This both
420  // sets the flags and leaves the object type in the type_reg register.  It
421  // leaves the heap object in the heap_object register unless the heap_object
422  // register is the same register as type_reg.
423  void CompareInstanceType(Register map,
424                           Register type_reg,
425                           InstanceType type);
426
427
428  // Check if the map of an object is equal to a specified map (either
429  // given directly or as an index into the root list) and branch to
430  // label if not. Skip the smi check if not required (object is known
431  // to be a heap object)
432  void CheckMap(Register obj,
433                Register scratch,
434                Handle<Map> map,
435                Label* fail,
436                bool is_heap_object);
437
438  void CheckMap(Register obj,
439                Register scratch,
440                Heap::RootListIndex index,
441                Label* fail,
442                bool is_heap_object);
443
444
445  // Load and check the instance type of an object for being a string.
446  // Loads the type into the second argument register.
447  // Returns a condition that will be enabled if the object was a string.
448  Condition IsObjectStringType(Register obj,
449                               Register type) {
450    ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
451    ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
452    tst(type, Operand(kIsNotStringMask));
453    ASSERT_EQ(0, kStringTag);
454    return eq;
455  }
456
457
458  inline void BranchOnSmi(Register value, Label* smi_label) {
459    tst(value, Operand(kSmiTagMask));
460    b(eq, smi_label);
461  }
462
463  inline void BranchOnNotSmi(Register value, Label* not_smi_label) {
464    tst(value, Operand(kSmiTagMask));
465    b(ne, not_smi_label);
466  }
467
468  // Generates code for reporting that an illegal operation has
469  // occurred.
470  void IllegalOperation(int num_arguments);
471
472  // Picks out an array index from the hash field.
473  // Register use:
474  //   hash - holds the index's hash. Clobbered.
475  //   index - holds the overwritten index on exit.
476  void IndexFromHash(Register hash, Register index);
477
478  // Get the number of least significant bits from a register
479  void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
480
481  // Uses VFP instructions to Convert a Smi to a double.
482  void IntegerToDoubleConversionWithVFP3(Register inReg,
483                                         Register outHighReg,
484                                         Register outLowReg);
485
486  // Load the value of a number object into a VFP double register. If the object
487  // is not a number a jump to the label not_number is performed and the VFP
488  // double register is unchanged.
489  void ObjectToDoubleVFPRegister(
490      Register object,
491      DwVfpRegister value,
492      Register scratch1,
493      Register scratch2,
494      Register heap_number_map,
495      SwVfpRegister scratch3,
496      Label* not_number,
497      ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS);
498
499  // Load the value of a smi object into a VFP double register. The register
500  // scratch1 can be the same register as smi in which case smi will hold the
501  // untagged value afterwards.
502  void SmiToDoubleVFPRegister(Register smi,
503                              DwVfpRegister value,
504                              Register scratch1,
505                              SwVfpRegister scratch2);
506
507  // Convert the HeapNumber pointed to by source to a 32bits signed integer
508  // dest. If the HeapNumber does not fit into a 32bits signed integer branch
509  // to not_int32 label.
510  void ConvertToInt32(Register source,
511                      Register dest,
512                      Register scratch,
513                      Register scratch2,
514                      Label *not_int32);
515
516  // Count leading zeros in a 32 bit word.  On ARM5 and later it uses the clz
517  // instruction.  On pre-ARM5 hardware this routine gives the wrong answer
518  // for 0 (31 instead of 32).  Source and scratch can be the same in which case
519  // the source is clobbered.  Source and zeros can also be the same in which
520  // case scratch should be a different register.
521  void CountLeadingZeros(Register zeros,
522                         Register source,
523                         Register scratch);
524
525  // ---------------------------------------------------------------------------
526  // Runtime calls
527
528  // Call a code stub.
529  void CallStub(CodeStub* stub, Condition cond = al);
530
531  // Call a code stub.
532  void TailCallStub(CodeStub* stub, Condition cond = al);
533
534  // Call a runtime routine.
535  void CallRuntime(Runtime::Function* f, int num_arguments);
536
537  // Convenience function: Same as above, but takes the fid instead.
538  void CallRuntime(Runtime::FunctionId fid, int num_arguments);
539
540  // Convenience function: call an external reference.
541  void CallExternalReference(const ExternalReference& ext,
542                             int num_arguments);
543
544  // Tail call of a runtime routine (jump).
545  // Like JumpToExternalReference, but also takes care of passing the number
546  // of parameters.
547  void TailCallExternalReference(const ExternalReference& ext,
548                                 int num_arguments,
549                                 int result_size);
550
551  // Convenience function: tail call a runtime routine (jump).
552  void TailCallRuntime(Runtime::FunctionId fid,
553                       int num_arguments,
554                       int result_size);
555
556  // Before calling a C-function from generated code, align arguments on stack.
557  // After aligning the frame, non-register arguments must be stored in
558  // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
559  // are word sized.
560  // Some compilers/platforms require the stack to be aligned when calling
561  // C++ code.
562  // Needs a scratch register to do some arithmetic. This register will be
563  // trashed.
564  void PrepareCallCFunction(int num_arguments, Register scratch);
565
566  // Calls a C function and cleans up the space for arguments allocated
567  // by PrepareCallCFunction. The called function is not allowed to trigger a
568  // garbage collection, since that might move the code and invalidate the
569  // return address (unless this is somehow accounted for by the called
570  // function).
571  void CallCFunction(ExternalReference function, int num_arguments);
572  void CallCFunction(Register function, int num_arguments);
573
574  // Jump to a runtime routine.
575  void JumpToExternalReference(const ExternalReference& builtin);
576
577  // Invoke specified builtin JavaScript function. Adds an entry to
578  // the unresolved list if the name does not resolve.
579  void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
580
581  // Store the code object for the given builtin in the target register and
582  // setup the function in r1.
583  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
584
585  // Store the function for the given builtin in the target register.
586  void GetBuiltinFunction(Register target, Builtins::JavaScript id);
587
588  Handle<Object> CodeObject() { return code_object_; }
589
590
591  // ---------------------------------------------------------------------------
592  // StatsCounter support
593
594  void SetCounter(StatsCounter* counter, int value,
595                  Register scratch1, Register scratch2);
596  void IncrementCounter(StatsCounter* counter, int value,
597                        Register scratch1, Register scratch2);
598  void DecrementCounter(StatsCounter* counter, int value,
599                        Register scratch1, Register scratch2);
600
601
602  // ---------------------------------------------------------------------------
603  // Debugging
604
605  // Calls Abort(msg) if the condition cc is not satisfied.
606  // Use --debug_code to enable.
607  void Assert(Condition cc, const char* msg);
608  void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
609  void AssertFastElements(Register elements);
610
611  // Like Assert(), but always enabled.
612  void Check(Condition cc, const char* msg);
613
614  // Print a message to stdout and abort execution.
615  void Abort(const char* msg);
616
617  // Verify restrictions about code generated in stubs.
618  void set_generating_stub(bool value) { generating_stub_ = value; }
619  bool generating_stub() { return generating_stub_; }
620  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
621  bool allow_stub_calls() { return allow_stub_calls_; }
622
623  // ---------------------------------------------------------------------------
624  // Smi utilities
625
626  // Jump if either of the registers contain a non-smi.
627  void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
628  // Jump if either of the registers contain a smi.
629  void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
630
631  // Abort execution if argument is a smi. Used in debug code.
632  void AbortIfSmi(Register object);
633
634  // ---------------------------------------------------------------------------
635  // String utilities
636
637  // Checks if both objects are sequential ASCII strings and jumps to label
638  // if either is not. Assumes that neither object is a smi.
639  void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
640                                                  Register object2,
641                                                  Register scratch1,
642                                                  Register scratch2,
643                                                  Label* failure);
644
645  // Checks if both objects are sequential ASCII strings and jumps to label
646  // if either is not.
647  void JumpIfNotBothSequentialAsciiStrings(Register first,
648                                           Register second,
649                                           Register scratch1,
650                                           Register scratch2,
651                                           Label* not_flat_ascii_strings);
652
653  // Checks if both instance types are sequential ASCII strings and jumps to
654  // label if either is not.
655  void JumpIfBothInstanceTypesAreNotSequentialAscii(
656      Register first_object_instance_type,
657      Register second_object_instance_type,
658      Register scratch1,
659      Register scratch2,
660      Label* failure);
661
662  // Check if instance type is sequential ASCII string and jump to label if
663  // it is not.
664  void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
665                                              Register scratch,
666                                              Label* failure);
667
668
669 private:
670  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
671  void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
672
673  // Helper functions for generating invokes.
674  void InvokePrologue(const ParameterCount& expected,
675                      const ParameterCount& actual,
676                      Handle<Code> code_constant,
677                      Register code_reg,
678                      Label* done,
679                      InvokeFlag flag);
680
681  // Activation support.
682  void EnterFrame(StackFrame::Type type);
683  void LeaveFrame(StackFrame::Type type);
684
685  void InitializeNewString(Register string,
686                           Register length,
687                           Heap::RootListIndex map_index,
688                           Register scratch1,
689                           Register scratch2);
690
691  bool generating_stub_;
692  bool allow_stub_calls_;
693  // This handle will be patched with the code object on installation.
694  Handle<Object> code_object_;
695};
696
697
698#ifdef ENABLE_DEBUGGER_SUPPORT
699// The code patcher is used to patch (typically) small parts of code e.g. for
700// debugging and other types of instrumentation. When using the code patcher
701// the exact number of bytes specified must be emitted. It is not legal to emit
702// relocation information. If any of these constraints are violated it causes
703// an assertion to fail.
704class CodePatcher {
705 public:
706  CodePatcher(byte* address, int instructions);
707  virtual ~CodePatcher();
708
709  // Macro assembler to emit code.
710  MacroAssembler* masm() { return &masm_; }
711
712  // Emit an instruction directly.
713  void Emit(Instr x);
714
715  // Emit an address directly.
716  void Emit(Address addr);
717
718 private:
719  byte* address_;  // The address of the code being patched.
720  int instructions_;  // Number of instructions of the expected patch size.
721  int size_;  // Number of bytes of the expected patch size.
722  MacroAssembler masm_;  // Macro assembler used to generate the code.
723};
724#endif  // ENABLE_DEBUGGER_SUPPORT
725
726
727// -----------------------------------------------------------------------------
728// Static helper functions.
729
730#ifdef GENERATED_CODE_COVERAGE
731#define CODE_COVERAGE_STRINGIFY(x) #x
732#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
733#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
734#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
735#else
736#define ACCESS_MASM(masm) masm->
737#endif
738
739
740} }  // namespace v8::internal
741
742#endif  // V8_ARM_MACRO_ASSEMBLER_ARM_H_
743