macro-assembler-arm.h revision d0582a6c46733687d045e4188a1bcd0123c758a1
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// Give alias names to registers
38const Register cp = { 8 };  // JavaScript context pointer
39
40
41enum InvokeJSFlags {
42  CALL_JS,
43  JUMP_JS
44};
45
46
47// MacroAssembler implements a collection of frequently used macros.
48class MacroAssembler: public Assembler {
49 public:
50  MacroAssembler(void* buffer, int size);
51
52  // ---------------------------------------------------------------------------
53  // Low-level helpers for compiler
54
55  // Jump, Call, and Ret pseudo instructions implementing inter-working
56 private:
57  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
58  void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
59 public:
60  void Jump(Register target, Condition cond = al);
61  void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
62  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
63  void Call(Register target, Condition cond = al);
64  void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
65  void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
66  void Ret(Condition cond = al);
67  // Jumps to the label at the index given by the Smi in "index".
68  void SmiJumpTable(Register index, Vector<Label*> targets);
69  // Load an object from the root table.
70  void LoadRoot(Register destination,
71                Heap::RootListIndex index,
72                Condition cond = al);
73
74  // Sets the remembered set bit for [address+offset], where address is the
75  // address of the heap object 'object'.  The address must be in the first 8K
76  // of an allocated page. The 'scratch' register is used in the
77  // implementation and all 3 registers are clobbered by the operation, as
78  // well as the ip register.
79  void RecordWrite(Register object, Register offset, Register scratch);
80
81  // ---------------------------------------------------------------------------
82  // Stack limit support
83
84  void StackLimitCheck(Label* on_stack_limit_hit);
85
86  // ---------------------------------------------------------------------------
87  // Activation frames
88
89  void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
90  void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
91
92  void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
93  void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
94
95  // Enter specific kind of exit frame; either normal or debug mode.
96  // Expects the number of arguments in register r0 and
97  // the builtin function to call in register r1. Exits with argc in
98  // r4, argv in r6, and and the builtin function to call in r5.
99  void EnterExitFrame(ExitFrame::Mode mode);
100
101  // Leave the current exit frame. Expects the return value in r0.
102  void LeaveExitFrame(ExitFrame::Mode mode);
103
104  // Align the stack by optionally pushing a Smi zero.
105  void AlignStack(int offset);
106
107  void LoadContext(Register dst, int context_chain_length);
108
109  // ---------------------------------------------------------------------------
110  // JavaScript invokes
111
112  // Invoke the JavaScript function code by either calling or jumping.
113  void InvokeCode(Register code,
114                  const ParameterCount& expected,
115                  const ParameterCount& actual,
116                  InvokeFlag flag);
117
118  void InvokeCode(Handle<Code> code,
119                  const ParameterCount& expected,
120                  const ParameterCount& actual,
121                  RelocInfo::Mode rmode,
122                  InvokeFlag flag);
123
124  // Invoke the JavaScript function in the given register. Changes the
125  // current context to the context in the function before invoking.
126  void InvokeFunction(Register function,
127                      const ParameterCount& actual,
128                      InvokeFlag flag);
129
130
131#ifdef ENABLE_DEBUGGER_SUPPORT
132  // ---------------------------------------------------------------------------
133  // Debugger Support
134
135  void SaveRegistersToMemory(RegList regs);
136  void RestoreRegistersFromMemory(RegList regs);
137  void CopyRegistersFromMemoryToStack(Register base, RegList regs);
138  void CopyRegistersFromStackToMemory(Register base,
139                                      Register scratch,
140                                      RegList regs);
141#endif
142
143  // ---------------------------------------------------------------------------
144  // Exception handling
145
146  // Push a new try handler and link into try handler chain.
147  // The return address must be passed in register lr.
148  // On exit, r0 contains TOS (code slot).
149  void PushTryHandler(CodeLocation try_location, HandlerType type);
150
151
152  // ---------------------------------------------------------------------------
153  // Inline caching support
154
155  // Generates code that verifies that the maps of objects in the
156  // prototype chain of object hasn't changed since the code was
157  // generated and branches to the miss label if any map has. If
158  // necessary the function also generates code for security check
159  // in case of global object holders. The scratch and holder
160  // registers are always clobbered, but the object register is only
161  // clobbered if it the same as the holder register. The function
162  // returns a register containing the holder - either object_reg or
163  // holder_reg.
164  Register CheckMaps(JSObject* object, Register object_reg,
165                     JSObject* holder, Register holder_reg,
166                     Register scratch, Label* miss);
167
168  // Generate code for checking access rights - used for security checks
169  // on access to global objects across environments. The holder register
170  // is left untouched, whereas both scratch registers are clobbered.
171  void CheckAccessGlobalProxy(Register holder_reg,
172                              Register scratch,
173                              Label* miss);
174
175
176  // ---------------------------------------------------------------------------
177  // Allocation support
178
179  // Allocate an object in new space. The object_size is specified in words (not
180  // bytes). If the new space is exhausted control continues at the gc_required
181  // label. The allocated object is returned in result. If the flag
182  // tag_allocated_object is true the result is tagged as as a heap object.
183  void AllocateInNewSpace(int object_size,
184                          Register result,
185                          Register scratch1,
186                          Register scratch2,
187                          Label* gc_required,
188                          AllocationFlags flags);
189  void AllocateInNewSpace(Register object_size,
190                          Register result,
191                          Register scratch1,
192                          Register scratch2,
193                          Label* gc_required,
194                          AllocationFlags flags);
195
196  // Undo allocation in new space. The object passed and objects allocated after
197  // it will no longer be allocated. The caller must make sure that no pointers
198  // are left to the object(s) no longer allocated as they would be invalid when
199  // allocation is undone.
200  void UndoAllocationInNewSpace(Register object, Register scratch);
201
202  // ---------------------------------------------------------------------------
203  // Support functions.
204
205  // Try to get function prototype of a function and puts the value in
206  // the result register. Checks that the function really is a
207  // function and jumps to the miss label if the fast checks fail. The
208  // function register will be untouched; the other registers may be
209  // clobbered.
210  void TryGetFunctionPrototype(Register function,
211                               Register result,
212                               Register scratch,
213                               Label* miss);
214
215  // Compare object type for heap object.  heap_object contains a non-Smi
216  // whose object type should be compared with the given type.  This both
217  // sets the flags and leaves the object type in the type_reg register.
218  // It leaves the map in the map register (unless the type_reg and map register
219  // are the same register).  It leaves the heap object in the heap_object
220  // register unless the heap_object register is the same register as one of the
221  // other registers.
222  void CompareObjectType(Register heap_object,
223                         Register map,
224                         Register type_reg,
225                         InstanceType type);
226
227  // Compare instance type in a map.  map contains a valid map object whose
228  // object type should be compared with the given type.  This both
229  // sets the flags and leaves the object type in the type_reg register.  It
230  // leaves the heap object in the heap_object register unless the heap_object
231  // register is the same register as type_reg.
232  void CompareInstanceType(Register map,
233                           Register type_reg,
234                           InstanceType type);
235
236  inline void BranchOnSmi(Register value, Label* smi_label) {
237    tst(value, Operand(kSmiTagMask));
238    b(eq, smi_label);
239  }
240
241  inline void BranchOnNotSmi(Register value, Label* not_smi_label) {
242    tst(value, Operand(kSmiTagMask));
243    b(ne, not_smi_label);
244  }
245
246  // Generates code for reporting that an illegal operation has
247  // occurred.
248  void IllegalOperation(int num_arguments);
249
250  // Uses VFP instructions to Convert a Smi to a double.
251  void IntegerToDoubleConversionWithVFP3(Register inReg,
252                                         Register outHighReg,
253                                         Register outLowReg);
254
255
256  // ---------------------------------------------------------------------------
257  // Runtime calls
258
259  // Call a code stub.
260  void CallStub(CodeStub* stub, Condition cond = al);
261
262  // Return from a code stub after popping its arguments.
263  void StubReturn(int argc);
264
265  // Call a runtime routine.
266  // Eventually this should be used for all C calls.
267  void CallRuntime(Runtime::Function* f, int num_arguments);
268
269  // Convenience function: Same as above, but takes the fid instead.
270  void CallRuntime(Runtime::FunctionId fid, int num_arguments);
271
272  // Tail call of a runtime routine (jump).
273  // Like JumpToRuntime, but also takes care of passing the number
274  // of parameters.
275  void TailCallRuntime(const ExternalReference& ext,
276                       int num_arguments,
277                       int result_size);
278
279  // Jump to a runtime routine.
280  void JumpToRuntime(const ExternalReference& builtin);
281
282  // Invoke specified builtin JavaScript function. Adds an entry to
283  // the unresolved list if the name does not resolve.
284  void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
285
286  // Store the code object for the given builtin in the target register and
287  // setup the function in r1.
288  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
289
290  struct Unresolved {
291    int pc;
292    uint32_t flags;  // see Bootstrapper::FixupFlags decoders/encoders.
293    const char* name;
294  };
295  List<Unresolved>* unresolved() { return &unresolved_; }
296
297  Handle<Object> CodeObject() { return code_object_; }
298
299
300  // ---------------------------------------------------------------------------
301  // StatsCounter support
302
303  void SetCounter(StatsCounter* counter, int value,
304                  Register scratch1, Register scratch2);
305  void IncrementCounter(StatsCounter* counter, int value,
306                        Register scratch1, Register scratch2);
307  void DecrementCounter(StatsCounter* counter, int value,
308                        Register scratch1, Register scratch2);
309
310
311  // ---------------------------------------------------------------------------
312  // Debugging
313
314  // Calls Abort(msg) if the condition cc is not satisfied.
315  // Use --debug_code to enable.
316  void Assert(Condition cc, const char* msg);
317
318  // Like Assert(), but always enabled.
319  void Check(Condition cc, const char* msg);
320
321  // Print a message to stdout and abort execution.
322  void Abort(const char* msg);
323
324  // Verify restrictions about code generated in stubs.
325  void set_generating_stub(bool value) { generating_stub_ = value; }
326  bool generating_stub() { return generating_stub_; }
327  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
328  bool allow_stub_calls() { return allow_stub_calls_; }
329
330 private:
331  List<Unresolved> unresolved_;
332  bool generating_stub_;
333  bool allow_stub_calls_;
334  Handle<Object> code_object_;  // This handle will be patched with the code
335                                // object on installation.
336
337  // Helper functions for generating invokes.
338  void InvokePrologue(const ParameterCount& expected,
339                      const ParameterCount& actual,
340                      Handle<Code> code_constant,
341                      Register code_reg,
342                      Label* done,
343                      InvokeFlag flag);
344
345  // Prepares for a call or jump to a builtin by doing two things:
346  // 1. Emits code that fetches the builtin's function object from the context
347  //    at runtime, and puts it in the register rdi.
348  // 2. Fetches the builtin's code object, and returns it in a handle, at
349  //    compile time, so that later code can emit instructions to jump or call
350  //    the builtin directly.  If the code object has not yet been created, it
351  //    returns the builtin code object for IllegalFunction, and sets the
352  //    output parameter "resolved" to false.  Code that uses the return value
353  //    should then add the address and the builtin name to the list of fixups
354  //    called unresolved_, which is fixed up by the bootstrapper.
355  Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
356
357  // Activation support.
358  void EnterFrame(StackFrame::Type type);
359  void LeaveFrame(StackFrame::Type type);
360};
361
362
363#ifdef ENABLE_DEBUGGER_SUPPORT
364// The code patcher is used to patch (typically) small parts of code e.g. for
365// debugging and other types of instrumentation. When using the code patcher
366// the exact number of bytes specified must be emitted. It is not legal to emit
367// relocation information. If any of these constraints are violated it causes
368// an assertion to fail.
369class CodePatcher {
370 public:
371  CodePatcher(byte* address, int instructions);
372  virtual ~CodePatcher();
373
374  // Macro assembler to emit code.
375  MacroAssembler* masm() { return &masm_; }
376
377  // Emit an instruction directly.
378  void Emit(Instr x);
379
380  // Emit an address directly.
381  void Emit(Address addr);
382
383 private:
384  byte* address_;  // The address of the code being patched.
385  int instructions_;  // Number of instructions of the expected patch size.
386  int size_;  // Number of bytes of the expected patch size.
387  MacroAssembler masm_;  // Macro assembler used to generate the code.
388};
389#endif  // ENABLE_DEBUGGER_SUPPORT
390
391
392// -----------------------------------------------------------------------------
393// Static helper functions.
394
395// Generate a MemOperand for loading a field from an object.
396static inline MemOperand FieldMemOperand(Register object, int offset) {
397  return MemOperand(object, offset - kHeapObjectTag);
398}
399
400
401#ifdef GENERATED_CODE_COVERAGE
402#define CODE_COVERAGE_STRINGIFY(x) #x
403#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
404#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
405#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
406#else
407#define ACCESS_MASM(masm) masm->
408#endif
409
410
411} }  // namespace v8::internal
412
413#endif  // V8_ARM_MACRO_ASSEMBLER_ARM_H_
414