macro-assembler-arm.h revision 402d937239b0e2fd11bf2f4fe972ad78aa9fd481
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// MacroAssembler implements a collection of frequently used macros.
56class MacroAssembler: public Assembler {
57 public:
58  MacroAssembler(void* buffer, int size);
59
60  // Jump, Call, and Ret pseudo instructions implementing inter-working.
61  void Jump(Register target, Condition cond = al);
62  void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
63  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
64  void Call(Register target, Condition cond = al);
65  void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
66  void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
67  void Ret(Condition cond = al);
68
69  // Emit code to discard a non-negative number of pointer-sized elements
70  // from the stack, clobbering only the sp register.
71  void Drop(int count, Condition cond = al);
72
73  void Call(Label* target);
74  void Move(Register dst, Handle<Object> value);
75  // Jumps to the label at the index given by the Smi in "index".
76  void SmiJumpTable(Register index, Vector<Label*> targets);
77  // Load an object from the root table.
78  void LoadRoot(Register destination,
79                Heap::RootListIndex index,
80                Condition cond = al);
81
82  // Sets the remembered set bit for [address+offset], where address is the
83  // address of the heap object 'object'.  The address must be in the first 8K
84  // of an allocated page. The 'scratch' register is used in the
85  // implementation and all 3 registers are clobbered by the operation, as
86  // well as the ip register.
87  void RecordWrite(Register object, Register offset, Register scratch);
88
89  // ---------------------------------------------------------------------------
90  // Stack limit support
91
92  void StackLimitCheck(Label* on_stack_limit_hit);
93
94  // ---------------------------------------------------------------------------
95  // Activation frames
96
97  void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
98  void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
99
100  void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
101  void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
102
103  // Enter specific kind of exit frame; either normal or debug mode.
104  // Expects the number of arguments in register r0 and
105  // the builtin function to call in register r1. Exits with argc in
106  // r4, argv in r6, and and the builtin function to call in r5.
107  void EnterExitFrame(ExitFrame::Mode mode);
108
109  // Leave the current exit frame. Expects the return value in r0.
110  void LeaveExitFrame(ExitFrame::Mode mode);
111
112  // Align the stack by optionally pushing a Smi zero.
113  void AlignStack(int offset);
114
115  void LoadContext(Register dst, int context_chain_length);
116
117  // ---------------------------------------------------------------------------
118  // JavaScript invokes
119
120  // Invoke the JavaScript function code by either calling or jumping.
121  void InvokeCode(Register code,
122                  const ParameterCount& expected,
123                  const ParameterCount& actual,
124                  InvokeFlag flag);
125
126  void InvokeCode(Handle<Code> code,
127                  const ParameterCount& expected,
128                  const ParameterCount& actual,
129                  RelocInfo::Mode rmode,
130                  InvokeFlag flag);
131
132  // Invoke the JavaScript function in the given register. Changes the
133  // current context to the context in the function before invoking.
134  void InvokeFunction(Register function,
135                      const ParameterCount& actual,
136                      InvokeFlag flag);
137
138  void InvokeFunction(JSFunction* function,
139                      const ParameterCount& actual,
140                      InvokeFlag flag);
141
142
143#ifdef ENABLE_DEBUGGER_SUPPORT
144  // ---------------------------------------------------------------------------
145  // Debugger Support
146
147  void SaveRegistersToMemory(RegList regs);
148  void RestoreRegistersFromMemory(RegList regs);
149  void CopyRegistersFromMemoryToStack(Register base, RegList regs);
150  void CopyRegistersFromStackToMemory(Register base,
151                                      Register scratch,
152                                      RegList regs);
153  void DebugBreak();
154#endif
155
156  // ---------------------------------------------------------------------------
157  // Exception handling
158
159  // Push a new try handler and link into try handler chain.
160  // The return address must be passed in register lr.
161  // On exit, r0 contains TOS (code slot).
162  void PushTryHandler(CodeLocation try_location, HandlerType type);
163
164  // Unlink the stack handler on top of the stack from the try handler chain.
165  // Must preserve the result register.
166  void PopTryHandler();
167
168  // ---------------------------------------------------------------------------
169  // Inline caching support
170
171  // Generates code that verifies that the maps of objects in the
172  // prototype chain of object hasn't changed since the code was
173  // generated and branches to the miss label if any map has. If
174  // necessary the function also generates code for security check
175  // in case of global object holders. The scratch and holder
176  // registers are always clobbered, but the object register is only
177  // clobbered if it the same as the holder register. The function
178  // returns a register containing the holder - either object_reg or
179  // holder_reg.
180  Register CheckMaps(JSObject* object, Register object_reg,
181                     JSObject* holder, Register holder_reg,
182                     Register scratch, Label* miss);
183
184  // Generate code for checking access rights - used for security checks
185  // on access to global objects across environments. The holder register
186  // is left untouched, whereas both scratch registers are clobbered.
187  void CheckAccessGlobalProxy(Register holder_reg,
188                              Register scratch,
189                              Label* miss);
190
191
192  // ---------------------------------------------------------------------------
193  // Allocation support
194
195  // Allocate an object in new space. The object_size is specified in words (not
196  // bytes). If the new space is exhausted control continues at the gc_required
197  // label. The allocated object is returned in result. If the flag
198  // tag_allocated_object is true the result is tagged as as a heap object.
199  void AllocateInNewSpace(int object_size,
200                          Register result,
201                          Register scratch1,
202                          Register scratch2,
203                          Label* gc_required,
204                          AllocationFlags flags);
205  void AllocateInNewSpace(Register object_size,
206                          Register result,
207                          Register scratch1,
208                          Register scratch2,
209                          Label* gc_required,
210                          AllocationFlags flags);
211
212  // Undo allocation in new space. The object passed and objects allocated after
213  // it will no longer be allocated. The caller must make sure that no pointers
214  // are left to the object(s) no longer allocated as they would be invalid when
215  // allocation is undone.
216  void UndoAllocationInNewSpace(Register object, Register scratch);
217
218
219  void AllocateTwoByteString(Register result,
220                             Register length,
221                             Register scratch1,
222                             Register scratch2,
223                             Register scratch3,
224                             Label* gc_required);
225  void AllocateAsciiString(Register result,
226                           Register length,
227                           Register scratch1,
228                           Register scratch2,
229                           Register scratch3,
230                           Label* gc_required);
231  void AllocateTwoByteConsString(Register result,
232                                 Register length,
233                                 Register scratch1,
234                                 Register scratch2,
235                                 Label* gc_required);
236  void AllocateAsciiConsString(Register result,
237                               Register length,
238                               Register scratch1,
239                               Register scratch2,
240                               Label* gc_required);
241
242
243  // ---------------------------------------------------------------------------
244  // Support functions.
245
246  // Try to get function prototype of a function and puts the value in
247  // the result register. Checks that the function really is a
248  // function and jumps to the miss label if the fast checks fail. The
249  // function register will be untouched; the other registers may be
250  // clobbered.
251  void TryGetFunctionPrototype(Register function,
252                               Register result,
253                               Register scratch,
254                               Label* miss);
255
256  // Compare object type for heap object.  heap_object contains a non-Smi
257  // whose object type should be compared with the given type.  This both
258  // sets the flags and leaves the object type in the type_reg register.
259  // It leaves the map in the map register (unless the type_reg and map register
260  // are the same register).  It leaves the heap object in the heap_object
261  // register unless the heap_object register is the same register as one of the
262  // other registers.
263  void CompareObjectType(Register heap_object,
264                         Register map,
265                         Register type_reg,
266                         InstanceType type);
267
268  // Compare instance type in a map.  map contains a valid map object whose
269  // object type should be compared with the given type.  This both
270  // sets the flags and leaves the object type in the type_reg register.  It
271  // leaves the heap object in the heap_object register unless the heap_object
272  // register is the same register as type_reg.
273  void CompareInstanceType(Register map,
274                           Register type_reg,
275                           InstanceType type);
276
277
278  // Check if the map of an object is equal to a specified map and
279  // branch to label if not. Skip the smi check if not required
280  // (object is known to be a heap object)
281  void CheckMap(Register obj,
282                Register scratch,
283                Handle<Map> map,
284                Label* fail,
285                bool is_heap_object);
286
287  // Load and check the instance type of an object for being a string.
288  // Loads the type into the second argument register.
289  // Returns a condition that will be enabled if the object was a string.
290  Condition IsObjectStringType(Register obj,
291                               Register type) {
292    ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
293    ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
294    tst(type, Operand(kIsNotStringMask));
295    ASSERT_EQ(0, kStringTag);
296    return eq;
297  }
298
299
300  inline void BranchOnSmi(Register value, Label* smi_label) {
301    tst(value, Operand(kSmiTagMask));
302    b(eq, smi_label);
303  }
304
305  inline void BranchOnNotSmi(Register value, Label* not_smi_label) {
306    tst(value, Operand(kSmiTagMask));
307    b(ne, not_smi_label);
308  }
309
310  // Generates code for reporting that an illegal operation has
311  // occurred.
312  void IllegalOperation(int num_arguments);
313
314  // Get the number of least significant bits from a register
315  void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
316
317  // Uses VFP instructions to Convert a Smi to a double.
318  void IntegerToDoubleConversionWithVFP3(Register inReg,
319                                         Register outHighReg,
320                                         Register outLowReg);
321
322
323  // ---------------------------------------------------------------------------
324  // Runtime calls
325
326  // Call a code stub.
327  void CallStub(CodeStub* stub, Condition cond = al);
328
329  // Call a code stub.
330  void TailCallStub(CodeStub* stub, Condition cond = al);
331
332  // Return from a code stub after popping its arguments.
333  void StubReturn(int argc);
334
335  // Call a runtime routine.
336  // Eventually this should be used for all C calls.
337  void CallRuntime(Runtime::Function* f, int num_arguments);
338
339  // Convenience function: Same as above, but takes the fid instead.
340  void CallRuntime(Runtime::FunctionId fid, int num_arguments);
341
342  // Convenience function: call an external reference.
343  void CallExternalReference(const ExternalReference& ext,
344                             int num_arguments);
345
346  // Tail call of a runtime routine (jump).
347  // Like JumpToRuntime, but also takes care of passing the number
348  // of parameters.
349  void TailCallRuntime(const ExternalReference& ext,
350                       int num_arguments,
351                       int result_size);
352
353  // Jump to a runtime routine.
354  void JumpToRuntime(const ExternalReference& builtin);
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, InvokeJSFlags flags);
359
360  // Store the code object for the given builtin in the target register and
361  // setup the function in r1.
362  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
363
364  Handle<Object> CodeObject() { return code_object_; }
365
366
367  // ---------------------------------------------------------------------------
368  // StatsCounter support
369
370  void SetCounter(StatsCounter* counter, int value,
371                  Register scratch1, Register scratch2);
372  void IncrementCounter(StatsCounter* counter, int value,
373                        Register scratch1, Register scratch2);
374  void DecrementCounter(StatsCounter* counter, int value,
375                        Register scratch1, Register scratch2);
376
377
378  // ---------------------------------------------------------------------------
379  // Debugging
380
381  // Calls Abort(msg) if the condition cc is not satisfied.
382  // Use --debug_code to enable.
383  void Assert(Condition cc, const char* msg);
384
385  // Like Assert(), but always enabled.
386  void Check(Condition cc, const char* msg);
387
388  // Print a message to stdout and abort execution.
389  void Abort(const char* msg);
390
391  // Verify restrictions about code generated in stubs.
392  void set_generating_stub(bool value) { generating_stub_ = value; }
393  bool generating_stub() { return generating_stub_; }
394  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
395  bool allow_stub_calls() { return allow_stub_calls_; }
396
397  // ---------------------------------------------------------------------------
398  // Smi utilities
399
400  // Jump if either of the registers contain a non-smi.
401  void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
402  // Jump if either of the registers contain a smi.
403  void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
404
405  // ---------------------------------------------------------------------------
406  // String utilities
407
408  // Checks if both objects are sequential ASCII strings and jumps to label
409  // if either is not. Assumes that neither object is a smi.
410  void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
411                                                  Register object2,
412                                                  Register scratch1,
413                                                  Register scratch2,
414                                                  Label *failure);
415
416  // Checks if both objects are sequential ASCII strings and jumps to label
417  // if either is not.
418  void JumpIfNotBothSequentialAsciiStrings(Register first,
419                                           Register second,
420                                           Register scratch1,
421                                           Register scratch2,
422                                           Label* not_flat_ascii_strings);
423
424 private:
425  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
426  void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
427
428  // Helper functions for generating invokes.
429  void InvokePrologue(const ParameterCount& expected,
430                      const ParameterCount& actual,
431                      Handle<Code> code_constant,
432                      Register code_reg,
433                      Label* done,
434                      InvokeFlag flag);
435
436  // Activation support.
437  void EnterFrame(StackFrame::Type type);
438  void LeaveFrame(StackFrame::Type type);
439
440  bool generating_stub_;
441  bool allow_stub_calls_;
442  // This handle will be patched with the code object on installation.
443  Handle<Object> code_object_;
444};
445
446
447#ifdef ENABLE_DEBUGGER_SUPPORT
448// The code patcher is used to patch (typically) small parts of code e.g. for
449// debugging and other types of instrumentation. When using the code patcher
450// the exact number of bytes specified must be emitted. It is not legal to emit
451// relocation information. If any of these constraints are violated it causes
452// an assertion to fail.
453class CodePatcher {
454 public:
455  CodePatcher(byte* address, int instructions);
456  virtual ~CodePatcher();
457
458  // Macro assembler to emit code.
459  MacroAssembler* masm() { return &masm_; }
460
461  // Emit an instruction directly.
462  void Emit(Instr x);
463
464  // Emit an address directly.
465  void Emit(Address addr);
466
467 private:
468  byte* address_;  // The address of the code being patched.
469  int instructions_;  // Number of instructions of the expected patch size.
470  int size_;  // Number of bytes of the expected patch size.
471  MacroAssembler masm_;  // Macro assembler used to generate the code.
472};
473#endif  // ENABLE_DEBUGGER_SUPPORT
474
475
476// -----------------------------------------------------------------------------
477// Static helper functions.
478
479#ifdef GENERATED_CODE_COVERAGE
480#define CODE_COVERAGE_STRINGIFY(x) #x
481#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
482#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
483#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
484#else
485#define ACCESS_MASM(masm) masm->
486#endif
487
488
489} }  // namespace v8::internal
490
491#endif  // V8_ARM_MACRO_ASSEMBLER_ARM_H_
492