blob: 66ef4f9a24e95d1b5744742214f4e3e7b83c51f7 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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
Andrei Popescu31002712010-02-23 13:46:05 +000036// ----------------------------------------------------------------------------
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
Steve Blocka7e24c12009-10-30 11:49:00 +000044
45// Give alias names to registers
46const Register cp = { 8 }; // JavaScript context pointer
Andrei Popescu31002712010-02-23 13:46:05 +000047const Register roots = { 10 }; // Roots array pointer.
Steve Blocka7e24c12009-10-30 11:49:00 +000048
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
Andrei Popescu31002712010-02-23 13:46:05 +000060 // Jump, Call, and Ret pseudo instructions implementing inter-working.
Steve Blocka7e24c12009-10-30 11:49:00 +000061 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);
Leon Clarkee46be812010-01-19 14:06:41 +000068
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);
Steve Blocka7e24c12009-10-30 11:49:00 +000075 // 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 // ---------------------------------------------------------------------------
Steve Blockd0582a62009-12-15 09:54:21 +000090 // Stack limit support
91
92 void StackLimitCheck(Label* on_stack_limit_hit);
93
94 // ---------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +000095 // 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
Steve Blockd0582a62009-12-15 09:54:21 +0000103 // Enter specific kind of exit frame; either normal or debug mode.
104 // Expects the number of arguments in register r0 and
Steve Blocka7e24c12009-10-30 11:49:00 +0000105 // 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.
Steve Blockd0582a62009-12-15 09:54:21 +0000107 void EnterExitFrame(ExitFrame::Mode mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000108
109 // Leave the current exit frame. Expects the return value in r0.
Steve Blockd0582a62009-12-15 09:54:21 +0000110 void LeaveExitFrame(ExitFrame::Mode mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000111
112 // Align the stack by optionally pushing a Smi zero.
113 void AlignStack(int offset);
114
Steve Blockd0582a62009-12-15 09:54:21 +0000115 void LoadContext(Register dst, int context_chain_length);
116
Steve Blocka7e24c12009-10-30 11:49:00 +0000117 // ---------------------------------------------------------------------------
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
139#ifdef ENABLE_DEBUGGER_SUPPORT
140 // ---------------------------------------------------------------------------
141 // Debugger Support
142
143 void SaveRegistersToMemory(RegList regs);
144 void RestoreRegistersFromMemory(RegList regs);
145 void CopyRegistersFromMemoryToStack(Register base, RegList regs);
146 void CopyRegistersFromStackToMemory(Register base,
147 Register scratch,
148 RegList regs);
149#endif
150
151 // ---------------------------------------------------------------------------
152 // Exception handling
153
154 // Push a new try handler and link into try handler chain.
155 // The return address must be passed in register lr.
156 // On exit, r0 contains TOS (code slot).
157 void PushTryHandler(CodeLocation try_location, HandlerType type);
158
Leon Clarkee46be812010-01-19 14:06:41 +0000159 // Unlink the stack handler on top of the stack from the try handler chain.
160 // Must preserve the result register.
161 void PopTryHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000162
163 // ---------------------------------------------------------------------------
164 // Inline caching support
165
166 // Generates code that verifies that the maps of objects in the
167 // prototype chain of object hasn't changed since the code was
168 // generated and branches to the miss label if any map has. If
169 // necessary the function also generates code for security check
170 // in case of global object holders. The scratch and holder
171 // registers are always clobbered, but the object register is only
172 // clobbered if it the same as the holder register. The function
173 // returns a register containing the holder - either object_reg or
174 // holder_reg.
175 Register CheckMaps(JSObject* object, Register object_reg,
176 JSObject* holder, Register holder_reg,
177 Register scratch, Label* miss);
178
179 // Generate code for checking access rights - used for security checks
180 // on access to global objects across environments. The holder register
181 // is left untouched, whereas both scratch registers are clobbered.
182 void CheckAccessGlobalProxy(Register holder_reg,
183 Register scratch,
184 Label* miss);
185
186
187 // ---------------------------------------------------------------------------
188 // Allocation support
189
190 // Allocate an object in new space. The object_size is specified in words (not
191 // bytes). If the new space is exhausted control continues at the gc_required
192 // label. The allocated object is returned in result. If the flag
193 // tag_allocated_object is true the result is tagged as as a heap object.
194 void AllocateInNewSpace(int object_size,
195 Register result,
196 Register scratch1,
197 Register scratch2,
198 Label* gc_required,
199 AllocationFlags flags);
200 void AllocateInNewSpace(Register object_size,
201 Register result,
202 Register scratch1,
203 Register scratch2,
204 Label* gc_required,
205 AllocationFlags flags);
206
207 // Undo allocation in new space. The object passed and objects allocated after
208 // it will no longer be allocated. The caller must make sure that no pointers
209 // are left to the object(s) no longer allocated as they would be invalid when
210 // allocation is undone.
211 void UndoAllocationInNewSpace(Register object, Register scratch);
212
Andrei Popescu31002712010-02-23 13:46:05 +0000213
214 void AllocateTwoByteString(Register result,
215 Register length,
216 Register scratch1,
217 Register scratch2,
218 Register scratch3,
219 Label* gc_required);
220 void AllocateAsciiString(Register result,
221 Register length,
222 Register scratch1,
223 Register scratch2,
224 Register scratch3,
225 Label* gc_required);
226 void AllocateTwoByteConsString(Register result,
227 Register length,
228 Register scratch1,
229 Register scratch2,
230 Label* gc_required);
231 void AllocateAsciiConsString(Register result,
232 Register length,
233 Register scratch1,
234 Register scratch2,
235 Label* gc_required);
236
237
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 // ---------------------------------------------------------------------------
239 // Support functions.
240
241 // Try to get function prototype of a function and puts the value in
242 // the result register. Checks that the function really is a
243 // function and jumps to the miss label if the fast checks fail. The
244 // function register will be untouched; the other registers may be
245 // clobbered.
246 void TryGetFunctionPrototype(Register function,
247 Register result,
248 Register scratch,
249 Label* miss);
250
251 // Compare object type for heap object. heap_object contains a non-Smi
252 // whose object type should be compared with the given type. This both
253 // sets the flags and leaves the object type in the type_reg register.
254 // It leaves the map in the map register (unless the type_reg and map register
255 // are the same register). It leaves the heap object in the heap_object
256 // register unless the heap_object register is the same register as one of the
257 // other registers.
258 void CompareObjectType(Register heap_object,
259 Register map,
260 Register type_reg,
261 InstanceType type);
262
263 // Compare instance type in a map. map contains a valid map object whose
264 // object type should be compared with the given type. This both
265 // sets the flags and leaves the object type in the type_reg register. It
266 // leaves the heap object in the heap_object register unless the heap_object
267 // register is the same register as type_reg.
268 void CompareInstanceType(Register map,
269 Register type_reg,
270 InstanceType type);
271
Andrei Popescu31002712010-02-23 13:46:05 +0000272
273 // Check if the map of an object is equal to a specified map and
274 // branch to label if not. Skip the smi check if not required
275 // (object is known to be a heap object)
276 void CheckMap(Register obj,
277 Register scratch,
278 Handle<Map> map,
279 Label* fail,
280 bool is_heap_object);
281
282 // Load and check the instance type of an object for being a string.
283 // Loads the type into the second argument register.
284 // Returns a condition that will be enabled if the object was a string.
285 Condition IsObjectStringType(Register obj,
286 Register type) {
287 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
288 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
289 tst(type, Operand(kIsNotStringMask));
290 ASSERT_EQ(0, kStringTag);
291 return eq;
292 }
293
294
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 inline void BranchOnSmi(Register value, Label* smi_label) {
296 tst(value, Operand(kSmiTagMask));
297 b(eq, smi_label);
298 }
299
300 inline void BranchOnNotSmi(Register value, Label* not_smi_label) {
301 tst(value, Operand(kSmiTagMask));
302 b(ne, not_smi_label);
303 }
304
305 // Generates code for reporting that an illegal operation has
306 // occurred.
307 void IllegalOperation(int num_arguments);
308
Andrei Popescu31002712010-02-23 13:46:05 +0000309 // Get the number of least significant bits from a register
310 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
311
Steve Blockd0582a62009-12-15 09:54:21 +0000312 // Uses VFP instructions to Convert a Smi to a double.
313 void IntegerToDoubleConversionWithVFP3(Register inReg,
314 Register outHighReg,
315 Register outLowReg);
316
Steve Blocka7e24c12009-10-30 11:49:00 +0000317
318 // ---------------------------------------------------------------------------
319 // Runtime calls
320
321 // Call a code stub.
322 void CallStub(CodeStub* stub, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000323
Andrei Popescu31002712010-02-23 13:46:05 +0000324 // Call a code stub.
325 void TailCallStub(CodeStub* stub, Condition cond = al);
326
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 // Return from a code stub after popping its arguments.
328 void StubReturn(int argc);
329
330 // Call a runtime routine.
331 // Eventually this should be used for all C calls.
332 void CallRuntime(Runtime::Function* f, int num_arguments);
333
334 // Convenience function: Same as above, but takes the fid instead.
335 void CallRuntime(Runtime::FunctionId fid, int num_arguments);
336
337 // Tail call of a runtime routine (jump).
338 // Like JumpToRuntime, but also takes care of passing the number
339 // of parameters.
340 void TailCallRuntime(const ExternalReference& ext,
341 int num_arguments,
342 int result_size);
343
344 // Jump to a runtime routine.
345 void JumpToRuntime(const ExternalReference& builtin);
346
347 // Invoke specified builtin JavaScript function. Adds an entry to
348 // the unresolved list if the name does not resolve.
349 void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
350
351 // Store the code object for the given builtin in the target register and
352 // setup the function in r1.
353 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
354
355 struct Unresolved {
356 int pc;
357 uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
358 const char* name;
359 };
360 List<Unresolved>* unresolved() { return &unresolved_; }
361
362 Handle<Object> CodeObject() { return code_object_; }
363
364
365 // ---------------------------------------------------------------------------
366 // StatsCounter support
367
368 void SetCounter(StatsCounter* counter, int value,
369 Register scratch1, Register scratch2);
370 void IncrementCounter(StatsCounter* counter, int value,
371 Register scratch1, Register scratch2);
372 void DecrementCounter(StatsCounter* counter, int value,
373 Register scratch1, Register scratch2);
374
375
376 // ---------------------------------------------------------------------------
377 // Debugging
378
379 // Calls Abort(msg) if the condition cc is not satisfied.
380 // Use --debug_code to enable.
381 void Assert(Condition cc, const char* msg);
382
383 // Like Assert(), but always enabled.
384 void Check(Condition cc, const char* msg);
385
386 // Print a message to stdout and abort execution.
387 void Abort(const char* msg);
388
389 // Verify restrictions about code generated in stubs.
390 void set_generating_stub(bool value) { generating_stub_ = value; }
391 bool generating_stub() { return generating_stub_; }
392 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
393 bool allow_stub_calls() { return allow_stub_calls_; }
394
Leon Clarked91b9f72010-01-27 17:25:45 +0000395 // ---------------------------------------------------------------------------
Andrei Popescu31002712010-02-23 13:46:05 +0000396 // Smi utilities
397
398 // Jump if either of the registers contain a non-smi.
399 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
400 // Jump if either of the registers contain a smi.
401 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
402
403 // ---------------------------------------------------------------------------
Leon Clarked91b9f72010-01-27 17:25:45 +0000404 // String utilities
405
406 // Checks if both objects are sequential ASCII strings and jumps to label
407 // if either is not. Assumes that neither object is a smi.
408 void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
409 Register object2,
410 Register scratch1,
411 Register scratch2,
412 Label *failure);
413
414 // Checks if both objects are sequential ASCII strings and jumps to label
415 // if either is not.
416 void JumpIfNotBothSequentialAsciiStrings(Register first,
417 Register second,
418 Register scratch1,
419 Register scratch2,
420 Label* not_flat_ascii_strings);
421
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 private:
Andrei Popescu31002712010-02-23 13:46:05 +0000423 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
424 void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000425
426 // Helper functions for generating invokes.
427 void InvokePrologue(const ParameterCount& expected,
428 const ParameterCount& actual,
429 Handle<Code> code_constant,
430 Register code_reg,
431 Label* done,
432 InvokeFlag flag);
433
434 // Prepares for a call or jump to a builtin by doing two things:
435 // 1. Emits code that fetches the builtin's function object from the context
436 // at runtime, and puts it in the register rdi.
437 // 2. Fetches the builtin's code object, and returns it in a handle, at
438 // compile time, so that later code can emit instructions to jump or call
439 // the builtin directly. If the code object has not yet been created, it
440 // returns the builtin code object for IllegalFunction, and sets the
441 // output parameter "resolved" to false. Code that uses the return value
442 // should then add the address and the builtin name to the list of fixups
443 // called unresolved_, which is fixed up by the bootstrapper.
444 Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
445
446 // Activation support.
447 void EnterFrame(StackFrame::Type type);
448 void LeaveFrame(StackFrame::Type type);
Andrei Popescu31002712010-02-23 13:46:05 +0000449
450 List<Unresolved> unresolved_;
451 bool generating_stub_;
452 bool allow_stub_calls_;
453 // This handle will be patched with the code object on installation.
454 Handle<Object> code_object_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000455};
456
457
458#ifdef ENABLE_DEBUGGER_SUPPORT
459// The code patcher is used to patch (typically) small parts of code e.g. for
460// debugging and other types of instrumentation. When using the code patcher
461// the exact number of bytes specified must be emitted. It is not legal to emit
462// relocation information. If any of these constraints are violated it causes
463// an assertion to fail.
464class CodePatcher {
465 public:
466 CodePatcher(byte* address, int instructions);
467 virtual ~CodePatcher();
468
469 // Macro assembler to emit code.
470 MacroAssembler* masm() { return &masm_; }
471
472 // Emit an instruction directly.
473 void Emit(Instr x);
474
475 // Emit an address directly.
476 void Emit(Address addr);
477
478 private:
479 byte* address_; // The address of the code being patched.
480 int instructions_; // Number of instructions of the expected patch size.
481 int size_; // Number of bytes of the expected patch size.
482 MacroAssembler masm_; // Macro assembler used to generate the code.
483};
484#endif // ENABLE_DEBUGGER_SUPPORT
485
486
487// -----------------------------------------------------------------------------
488// Static helper functions.
489
Steve Blocka7e24c12009-10-30 11:49:00 +0000490#ifdef GENERATED_CODE_COVERAGE
491#define CODE_COVERAGE_STRINGIFY(x) #x
492#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
493#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
494#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
495#else
496#define ACCESS_MASM(masm) masm->
497#endif
498
499
500} } // namespace v8::internal
501
502#endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_