blob: 324fbb2dde9cdac4675ce28b473a8d1f2a9b0f74 [file] [log] [blame]
Ben Murdochb0fe1622011-05-05 13:52:32 +01001// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Ben Murdochb8e0da22011-05-16 14:20:40 +010036// Forward declaration.
37class PostCallGenerator;
38
Andrei Popescu31002712010-02-23 13:46:05 +000039// ----------------------------------------------------------------------------
40// Static helper functions
41
42// Generate a MemOperand for loading a field from an object.
43static inline MemOperand FieldMemOperand(Register object, int offset) {
44 return MemOperand(object, offset - kHeapObjectTag);
45}
46
Steve Blocka7e24c12009-10-30 11:49:00 +000047
48// Give alias names to registers
49const Register cp = { 8 }; // JavaScript context pointer
Andrei Popescu31002712010-02-23 13:46:05 +000050const Register roots = { 10 }; // Roots array pointer.
Steve Blocka7e24c12009-10-30 11:49:00 +000051
52enum InvokeJSFlags {
53 CALL_JS,
54 JUMP_JS
55};
56
57
Kristian Monsen25f61362010-05-21 11:50:48 +010058// Flags used for the AllocateInNewSpace functions.
59enum AllocationFlags {
60 // No special flags.
61 NO_ALLOCATION_FLAGS = 0,
62 // Return the pointer to the allocated already tagged as a heap object.
63 TAG_OBJECT = 1 << 0,
64 // The content of the result register already contains the allocation top in
65 // new space.
66 RESULT_CONTAINS_TOP = 1 << 1,
67 // Specify that the requested size of the space to allocate is specified in
68 // words instead of bytes.
69 SIZE_IN_WORDS = 1 << 2
70};
71
72
Steve Block8defd9f2010-07-08 12:39:36 +010073// Flags used for the ObjectToDoubleVFPRegister function.
74enum ObjectToDoubleFlags {
75 // No special flags.
76 NO_OBJECT_TO_DOUBLE_FLAGS = 0,
77 // Object is known to be a non smi.
78 OBJECT_NOT_SMI = 1 << 0,
79 // Don't load NaNs or infinities, branch to the non number case instead.
80 AVOID_NANS_AND_INFINITIES = 1 << 1
81};
82
83
Steve Blocka7e24c12009-10-30 11:49:00 +000084// MacroAssembler implements a collection of frequently used macros.
85class MacroAssembler: public Assembler {
86 public:
87 MacroAssembler(void* buffer, int size);
88
Andrei Popescu31002712010-02-23 13:46:05 +000089 // Jump, Call, and Ret pseudo instructions implementing inter-working.
Steve Blocka7e24c12009-10-30 11:49:00 +000090 void Jump(Register target, Condition cond = al);
91 void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
92 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
93 void Call(Register target, Condition cond = al);
94 void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
95 void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
96 void Ret(Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +000097
98 // Emit code to discard a non-negative number of pointer-sized elements
99 // from the stack, clobbering only the sp register.
100 void Drop(int count, Condition cond = al);
101
Ben Murdochb0fe1622011-05-05 13:52:32 +0100102 void Ret(int drop, Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100103
104 // Swap two registers. If the scratch register is omitted then a slightly
105 // less efficient form using xor instead of mov is emitted.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100106 void Swap(Register reg1,
107 Register reg2,
108 Register scratch = no_reg,
109 Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100110
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100111
112 void And(Register dst, Register src1, const Operand& src2,
113 Condition cond = al);
114 void Ubfx(Register dst, Register src, int lsb, int width,
115 Condition cond = al);
116 void Sbfx(Register dst, Register src, int lsb, int width,
117 Condition cond = al);
118 void Bfc(Register dst, int lsb, int width, Condition cond = al);
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100119 void Usat(Register dst, int satpos, const Operand& src,
120 Condition cond = al);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100121
Leon Clarkee46be812010-01-19 14:06:41 +0000122 void Call(Label* target);
123 void Move(Register dst, Handle<Object> value);
Steve Block6ded16b2010-05-10 14:33:55 +0100124 // May do nothing if the registers are identical.
125 void Move(Register dst, Register src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 // Jumps to the label at the index given by the Smi in "index".
127 void SmiJumpTable(Register index, Vector<Label*> targets);
128 // Load an object from the root table.
129 void LoadRoot(Register destination,
130 Heap::RootListIndex index,
131 Condition cond = al);
Kristian Monsen25f61362010-05-21 11:50:48 +0100132 // Store an object to the root table.
133 void StoreRoot(Register source,
134 Heap::RootListIndex index,
135 Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000136
Steve Block6ded16b2010-05-10 14:33:55 +0100137
138 // Check if object is in new space.
139 // scratch can be object itself, but it will be clobbered.
140 void InNewSpace(Register object,
141 Register scratch,
142 Condition cc, // eq for new space, ne otherwise
143 Label* branch);
144
145
Steve Block8defd9f2010-07-08 12:39:36 +0100146 // For the page containing |object| mark the region covering [address]
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100147 // dirty. The object address must be in the first 8K of an allocated page.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100148 void RecordWriteHelper(Register object,
Steve Block8defd9f2010-07-08 12:39:36 +0100149 Register address,
150 Register scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100151
Steve Block8defd9f2010-07-08 12:39:36 +0100152 // For the page containing |object| mark the region covering
153 // [object+offset] dirty. The object address must be in the first 8K
154 // of an allocated page. The 'scratch' registers are used in the
155 // implementation and all 3 registers are clobbered by the
156 // operation, as well as the ip register. RecordWrite updates the
157 // write barrier even when storing smis.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100158 void RecordWrite(Register object,
159 Operand offset,
160 Register scratch0,
161 Register scratch1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000162
Steve Block8defd9f2010-07-08 12:39:36 +0100163 // For the page containing |object| mark the region covering
164 // [address] dirty. The object address must be in the first 8K of an
165 // allocated page. All 3 registers are clobbered by the operation,
166 // as well as the ip register. RecordWrite updates the write barrier
167 // even when storing smis.
168 void RecordWrite(Register object,
169 Register address,
170 Register scratch);
171
Steve Block6ded16b2010-05-10 14:33:55 +0100172 // Push two registers. Pushes leftmost register first (to highest address).
173 void Push(Register src1, Register src2, Condition cond = al) {
174 ASSERT(!src1.is(src2));
175 if (src1.code() > src2.code()) {
176 stm(db_w, sp, src1.bit() | src2.bit(), cond);
177 } else {
178 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
179 str(src2, MemOperand(sp, 4, NegPreIndex), cond);
180 }
181 }
182
183 // Push three registers. Pushes leftmost register first (to highest address).
184 void Push(Register src1, Register src2, Register src3, Condition cond = al) {
185 ASSERT(!src1.is(src2));
186 ASSERT(!src2.is(src3));
187 ASSERT(!src1.is(src3));
188 if (src1.code() > src2.code()) {
189 if (src2.code() > src3.code()) {
190 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
191 } else {
192 stm(db_w, sp, src1.bit() | src2.bit(), cond);
193 str(src3, MemOperand(sp, 4, NegPreIndex), cond);
194 }
195 } else {
196 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
197 Push(src2, src3, cond);
198 }
199 }
200
201 // Push four registers. Pushes leftmost register first (to highest address).
202 void Push(Register src1, Register src2,
203 Register src3, Register src4, Condition cond = al) {
204 ASSERT(!src1.is(src2));
205 ASSERT(!src2.is(src3));
206 ASSERT(!src1.is(src3));
207 ASSERT(!src1.is(src4));
208 ASSERT(!src2.is(src4));
209 ASSERT(!src3.is(src4));
210 if (src1.code() > src2.code()) {
211 if (src2.code() > src3.code()) {
212 if (src3.code() > src4.code()) {
213 stm(db_w,
214 sp,
215 src1.bit() | src2.bit() | src3.bit() | src4.bit(),
216 cond);
217 } else {
218 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
219 str(src4, MemOperand(sp, 4, NegPreIndex), cond);
220 }
221 } else {
222 stm(db_w, sp, src1.bit() | src2.bit(), cond);
223 Push(src3, src4, cond);
224 }
225 } else {
226 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
227 Push(src2, src3, src4, cond);
228 }
229 }
230
Ben Murdochb0fe1622011-05-05 13:52:32 +0100231 // Push and pop the registers that can hold pointers, as defined by the
232 // RegList constant kSafepointSavedRegisters.
233 void PushSafepointRegisters();
234 void PopSafepointRegisters();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100235 void PushSafepointRegistersAndDoubles();
236 void PopSafepointRegistersAndDoubles();
237
Ben Murdochb0fe1622011-05-05 13:52:32 +0100238 static int SafepointRegisterStackIndex(int reg_code);
239
Leon Clarkef7060e22010-06-03 12:02:55 +0100240 // Load two consecutive registers with two consecutive memory locations.
241 void Ldrd(Register dst1,
242 Register dst2,
243 const MemOperand& src,
244 Condition cond = al);
245
246 // Store two consecutive registers to two consecutive memory locations.
247 void Strd(Register src1,
248 Register src2,
249 const MemOperand& dst,
250 Condition cond = al);
251
Ben Murdochb8e0da22011-05-16 14:20:40 +0100252 // Clear specified FPSCR bits.
253 void ClearFPSCRBits(const uint32_t bits_to_clear,
254 const Register scratch,
255 const Condition cond = al);
256
257 // Compare double values and move the result to the normal condition flags.
258 void VFPCompareAndSetFlags(const DwVfpRegister src1,
259 const DwVfpRegister src2,
260 const Condition cond = al);
261 void VFPCompareAndSetFlags(const DwVfpRegister src1,
262 const double src2,
263 const Condition cond = al);
264
265 // Compare double values and then load the fpscr flags to a register.
266 void VFPCompareAndLoadFlags(const DwVfpRegister src1,
267 const DwVfpRegister src2,
268 const Register fpscr_flags,
269 const Condition cond = al);
270 void VFPCompareAndLoadFlags(const DwVfpRegister src1,
271 const double src2,
272 const Register fpscr_flags,
273 const Condition cond = al);
274
Ben Murdoch086aeea2011-05-13 15:57:08 +0100275
Steve Blocka7e24c12009-10-30 11:49:00 +0000276 // ---------------------------------------------------------------------------
277 // Activation frames
278
279 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
280 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
281
282 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
283 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
284
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100285 // Enter exit frame.
Steve Blockd0582a62009-12-15 09:54:21 +0000286 // Expects the number of arguments in register r0 and
Steve Blocka7e24c12009-10-30 11:49:00 +0000287 // the builtin function to call in register r1. Exits with argc in
288 // r4, argv in r6, and and the builtin function to call in r5.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100289 void EnterExitFrame(bool save_doubles);
Steve Blocka7e24c12009-10-30 11:49:00 +0000290
291 // Leave the current exit frame. Expects the return value in r0.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100292 void LeaveExitFrame(bool save_doubles);
Steve Blocka7e24c12009-10-30 11:49:00 +0000293
Steve Block6ded16b2010-05-10 14:33:55 +0100294 // Get the actual activation frame alignment for target environment.
295 static int ActivationFrameAlignment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000296
Steve Blockd0582a62009-12-15 09:54:21 +0000297 void LoadContext(Register dst, int context_chain_length);
298
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800299 void LoadGlobalFunction(int index, Register function);
300
301 // Load the initial map from the global function. The registers
302 // function and map can be the same, function is then overwritten.
303 void LoadGlobalFunctionInitialMap(Register function,
304 Register map,
305 Register scratch);
306
Steve Blocka7e24c12009-10-30 11:49:00 +0000307 // ---------------------------------------------------------------------------
308 // JavaScript invokes
309
310 // Invoke the JavaScript function code by either calling or jumping.
311 void InvokeCode(Register code,
312 const ParameterCount& expected,
313 const ParameterCount& actual,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100314 InvokeFlag flag,
315 PostCallGenerator* post_call_generator = NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000316
317 void InvokeCode(Handle<Code> code,
318 const ParameterCount& expected,
319 const ParameterCount& actual,
320 RelocInfo::Mode rmode,
321 InvokeFlag flag);
322
323 // Invoke the JavaScript function in the given register. Changes the
324 // current context to the context in the function before invoking.
325 void InvokeFunction(Register function,
326 const ParameterCount& actual,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100327 InvokeFlag flag,
328 PostCallGenerator* post_call_generator = NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000329
Andrei Popescu402d9372010-02-26 13:31:12 +0000330 void InvokeFunction(JSFunction* function,
331 const ParameterCount& actual,
332 InvokeFlag flag);
333
Ben Murdochb0fe1622011-05-05 13:52:32 +0100334 void IsObjectJSObjectType(Register heap_object,
335 Register map,
336 Register scratch,
337 Label* fail);
338
339 void IsInstanceJSObjectType(Register map,
340 Register scratch,
341 Label* fail);
342
343 void IsObjectJSStringType(Register object,
344 Register scratch,
345 Label* fail);
Steve Blocka7e24c12009-10-30 11:49:00 +0000346
347#ifdef ENABLE_DEBUGGER_SUPPORT
348 // ---------------------------------------------------------------------------
349 // Debugger Support
350
Andrei Popescu402d9372010-02-26 13:31:12 +0000351 void DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +0000352#endif
353
354 // ---------------------------------------------------------------------------
355 // Exception handling
356
357 // Push a new try handler and link into try handler chain.
358 // The return address must be passed in register lr.
359 // On exit, r0 contains TOS (code slot).
360 void PushTryHandler(CodeLocation try_location, HandlerType type);
361
Leon Clarkee46be812010-01-19 14:06:41 +0000362 // Unlink the stack handler on top of the stack from the try handler chain.
363 // Must preserve the result register.
364 void PopTryHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000365
366 // ---------------------------------------------------------------------------
367 // Inline caching support
368
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 // Generate code for checking access rights - used for security checks
370 // on access to global objects across environments. The holder register
371 // is left untouched, whereas both scratch registers are clobbered.
372 void CheckAccessGlobalProxy(Register holder_reg,
373 Register scratch,
374 Label* miss);
375
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800376 inline void MarkCode(NopMarkerTypes type) {
377 nop(type);
378 }
379
380 // Check if the given instruction is a 'type' marker.
381 // ie. check if is is a mov r<type>, r<type> (referenced as nop(type))
382 // These instructions are generated to mark special location in the code,
383 // like some special IC code.
384 static inline bool IsMarkedCode(Instr instr, int type) {
385 ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
386 return IsNop(instr, type);
387 }
388
389
390 static inline int GetCodeMarker(Instr instr) {
391 int dst_reg_offset = 12;
392 int dst_mask = 0xf << dst_reg_offset;
393 int src_mask = 0xf;
394 int dst_reg = (instr & dst_mask) >> dst_reg_offset;
395 int src_reg = instr & src_mask;
396 uint32_t non_register_mask = ~(dst_mask | src_mask);
397 uint32_t mov_mask = al | 13 << 21;
398
399 // Return <n> if we have a mov rn rn, else return -1.
400 int type = ((instr & non_register_mask) == mov_mask) &&
401 (dst_reg == src_reg) &&
402 (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER)
403 ? src_reg
404 : -1;
405 ASSERT((type == -1) ||
406 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
407 return type;
408 }
409
Steve Blocka7e24c12009-10-30 11:49:00 +0000410
411 // ---------------------------------------------------------------------------
412 // Allocation support
413
Ben Murdoch086aeea2011-05-13 15:57:08 +0100414 // Allocate an object in new space. The object_size is specified
415 // either in bytes or in words if the allocation flag SIZE_IN_WORDS
416 // is passed. If the new space is exhausted control continues at the
417 // gc_required label. The allocated object is returned in result. If
418 // the flag tag_allocated_object is true the result is tagged as as
419 // a heap object. All registers are clobbered also when control
420 // continues at the gc_required label.
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 void AllocateInNewSpace(int object_size,
422 Register result,
423 Register scratch1,
424 Register scratch2,
425 Label* gc_required,
426 AllocationFlags flags);
427 void AllocateInNewSpace(Register object_size,
428 Register result,
429 Register scratch1,
430 Register scratch2,
431 Label* gc_required,
432 AllocationFlags flags);
433
434 // Undo allocation in new space. The object passed and objects allocated after
435 // it will no longer be allocated. The caller must make sure that no pointers
436 // are left to the object(s) no longer allocated as they would be invalid when
437 // allocation is undone.
438 void UndoAllocationInNewSpace(Register object, Register scratch);
439
Andrei Popescu31002712010-02-23 13:46:05 +0000440
441 void AllocateTwoByteString(Register result,
442 Register length,
443 Register scratch1,
444 Register scratch2,
445 Register scratch3,
446 Label* gc_required);
447 void AllocateAsciiString(Register result,
448 Register length,
449 Register scratch1,
450 Register scratch2,
451 Register scratch3,
452 Label* gc_required);
453 void AllocateTwoByteConsString(Register result,
454 Register length,
455 Register scratch1,
456 Register scratch2,
457 Label* gc_required);
458 void AllocateAsciiConsString(Register result,
459 Register length,
460 Register scratch1,
461 Register scratch2,
462 Label* gc_required);
463
Kristian Monsen25f61362010-05-21 11:50:48 +0100464 // Allocates a heap number or jumps to the gc_required label if the young
465 // space is full and a scavenge is needed. All registers are clobbered also
466 // when control continues at the gc_required label.
Steve Block6ded16b2010-05-10 14:33:55 +0100467 void AllocateHeapNumber(Register result,
468 Register scratch1,
469 Register scratch2,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100470 Register heap_number_map,
Steve Block6ded16b2010-05-10 14:33:55 +0100471 Label* gc_required);
Steve Block8defd9f2010-07-08 12:39:36 +0100472 void AllocateHeapNumberWithValue(Register result,
473 DwVfpRegister value,
474 Register scratch1,
475 Register scratch2,
476 Register heap_number_map,
477 Label* gc_required);
478
Ben Murdochbb769b22010-08-11 14:56:33 +0100479 // Copies a fixed number of fields of heap objects from src to dst.
480 void CopyFields(Register dst, Register src, RegList temps, int field_count);
Andrei Popescu31002712010-02-23 13:46:05 +0000481
Steve Blocka7e24c12009-10-30 11:49:00 +0000482 // ---------------------------------------------------------------------------
483 // Support functions.
484
485 // Try to get function prototype of a function and puts the value in
486 // the result register. Checks that the function really is a
487 // function and jumps to the miss label if the fast checks fail. The
488 // function register will be untouched; the other registers may be
489 // clobbered.
490 void TryGetFunctionPrototype(Register function,
491 Register result,
492 Register scratch,
493 Label* miss);
494
495 // Compare object type for heap object. heap_object contains a non-Smi
496 // whose object type should be compared with the given type. This both
497 // sets the flags and leaves the object type in the type_reg register.
498 // It leaves the map in the map register (unless the type_reg and map register
499 // are the same register). It leaves the heap object in the heap_object
500 // register unless the heap_object register is the same register as one of the
501 // other registers.
502 void CompareObjectType(Register heap_object,
503 Register map,
504 Register type_reg,
505 InstanceType type);
506
507 // Compare instance type in a map. map contains a valid map object whose
508 // object type should be compared with the given type. This both
509 // sets the flags and leaves the object type in the type_reg register. It
510 // leaves the heap object in the heap_object register unless the heap_object
511 // register is the same register as type_reg.
512 void CompareInstanceType(Register map,
513 Register type_reg,
514 InstanceType type);
515
Andrei Popescu31002712010-02-23 13:46:05 +0000516
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100517 // Check if the map of an object is equal to a specified map (either
518 // given directly or as an index into the root list) and branch to
519 // label if not. Skip the smi check if not required (object is known
520 // to be a heap object)
Andrei Popescu31002712010-02-23 13:46:05 +0000521 void CheckMap(Register obj,
522 Register scratch,
523 Handle<Map> map,
524 Label* fail,
525 bool is_heap_object);
526
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100527 void CheckMap(Register obj,
528 Register scratch,
529 Heap::RootListIndex index,
530 Label* fail,
531 bool is_heap_object);
532
533
Andrei Popescu31002712010-02-23 13:46:05 +0000534 // Load and check the instance type of an object for being a string.
535 // Loads the type into the second argument register.
536 // Returns a condition that will be enabled if the object was a string.
537 Condition IsObjectStringType(Register obj,
538 Register type) {
539 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
540 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
541 tst(type, Operand(kIsNotStringMask));
542 ASSERT_EQ(0, kStringTag);
543 return eq;
544 }
545
546
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 inline void BranchOnSmi(Register value, Label* smi_label) {
548 tst(value, Operand(kSmiTagMask));
549 b(eq, smi_label);
550 }
551
552 inline void BranchOnNotSmi(Register value, Label* not_smi_label) {
553 tst(value, Operand(kSmiTagMask));
554 b(ne, not_smi_label);
555 }
556
557 // Generates code for reporting that an illegal operation has
558 // occurred.
559 void IllegalOperation(int num_arguments);
560
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100561 // Picks out an array index from the hash field.
562 // Register use:
563 // hash - holds the index's hash. Clobbered.
564 // index - holds the overwritten index on exit.
565 void IndexFromHash(Register hash, Register index);
566
Andrei Popescu31002712010-02-23 13:46:05 +0000567 // Get the number of least significant bits from a register
568 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
569
Steve Blockd0582a62009-12-15 09:54:21 +0000570 // Uses VFP instructions to Convert a Smi to a double.
571 void IntegerToDoubleConversionWithVFP3(Register inReg,
572 Register outHighReg,
573 Register outLowReg);
574
Steve Block8defd9f2010-07-08 12:39:36 +0100575 // Load the value of a number object into a VFP double register. If the object
576 // is not a number a jump to the label not_number is performed and the VFP
577 // double register is unchanged.
578 void ObjectToDoubleVFPRegister(
579 Register object,
580 DwVfpRegister value,
581 Register scratch1,
582 Register scratch2,
583 Register heap_number_map,
584 SwVfpRegister scratch3,
585 Label* not_number,
586 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS);
587
588 // Load the value of a smi object into a VFP double register. The register
589 // scratch1 can be the same register as smi in which case smi will hold the
590 // untagged value afterwards.
591 void SmiToDoubleVFPRegister(Register smi,
592 DwVfpRegister value,
593 Register scratch1,
594 SwVfpRegister scratch2);
595
Iain Merrick9ac36c92010-09-13 15:29:50 +0100596 // Convert the HeapNumber pointed to by source to a 32bits signed integer
597 // dest. If the HeapNumber does not fit into a 32bits signed integer branch
598 // to not_int32 label.
599 void ConvertToInt32(Register source,
600 Register dest,
601 Register scratch,
602 Register scratch2,
603 Label *not_int32);
604
Steve Block6ded16b2010-05-10 14:33:55 +0100605 // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
606 // instruction. On pre-ARM5 hardware this routine gives the wrong answer
Steve Block8defd9f2010-07-08 12:39:36 +0100607 // for 0 (31 instead of 32). Source and scratch can be the same in which case
608 // the source is clobbered. Source and zeros can also be the same in which
609 // case scratch should be a different register.
610 void CountLeadingZeros(Register zeros,
611 Register source,
612 Register scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000613
614 // ---------------------------------------------------------------------------
615 // Runtime calls
616
617 // Call a code stub.
618 void CallStub(CodeStub* stub, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000619
Andrei Popescu31002712010-02-23 13:46:05 +0000620 // Call a code stub.
621 void TailCallStub(CodeStub* stub, Condition cond = al);
622
Steve Blocka7e24c12009-10-30 11:49:00 +0000623 // Call a runtime routine.
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 void CallRuntime(Runtime::Function* f, int num_arguments);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100625 void CallRuntimeSaveDoubles(Runtime::FunctionId id);
Steve Blocka7e24c12009-10-30 11:49:00 +0000626
627 // Convenience function: Same as above, but takes the fid instead.
628 void CallRuntime(Runtime::FunctionId fid, int num_arguments);
629
Andrei Popescu402d9372010-02-26 13:31:12 +0000630 // Convenience function: call an external reference.
631 void CallExternalReference(const ExternalReference& ext,
632 int num_arguments);
633
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 // Tail call of a runtime routine (jump).
Steve Block6ded16b2010-05-10 14:33:55 +0100635 // Like JumpToExternalReference, but also takes care of passing the number
Steve Blocka7e24c12009-10-30 11:49:00 +0000636 // of parameters.
Steve Block6ded16b2010-05-10 14:33:55 +0100637 void TailCallExternalReference(const ExternalReference& ext,
638 int num_arguments,
639 int result_size);
640
641 // Convenience function: tail call a runtime routine (jump).
642 void TailCallRuntime(Runtime::FunctionId fid,
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 int num_arguments,
644 int result_size);
645
Steve Block6ded16b2010-05-10 14:33:55 +0100646 // Before calling a C-function from generated code, align arguments on stack.
647 // After aligning the frame, non-register arguments must be stored in
648 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
649 // are word sized.
650 // Some compilers/platforms require the stack to be aligned when calling
651 // C++ code.
652 // Needs a scratch register to do some arithmetic. This register will be
653 // trashed.
654 void PrepareCallCFunction(int num_arguments, Register scratch);
655
656 // Calls a C function and cleans up the space for arguments allocated
657 // by PrepareCallCFunction. The called function is not allowed to trigger a
658 // garbage collection, since that might move the code and invalidate the
659 // return address (unless this is somehow accounted for by the called
660 // function).
661 void CallCFunction(ExternalReference function, int num_arguments);
662 void CallCFunction(Register function, int num_arguments);
663
Steve Blocka7e24c12009-10-30 11:49:00 +0000664 // Jump to a runtime routine.
Steve Block6ded16b2010-05-10 14:33:55 +0100665 void JumpToExternalReference(const ExternalReference& builtin);
Steve Blocka7e24c12009-10-30 11:49:00 +0000666
667 // Invoke specified builtin JavaScript function. Adds an entry to
668 // the unresolved list if the name does not resolve.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100669 void InvokeBuiltin(Builtins::JavaScript id,
670 InvokeJSFlags flags,
671 PostCallGenerator* post_call_generator = NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000672
673 // Store the code object for the given builtin in the target register and
674 // setup the function in r1.
675 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
676
Steve Block791712a2010-08-27 10:21:07 +0100677 // Store the function for the given builtin in the target register.
678 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
679
Steve Blocka7e24c12009-10-30 11:49:00 +0000680 Handle<Object> CodeObject() { return code_object_; }
681
682
683 // ---------------------------------------------------------------------------
684 // StatsCounter support
685
686 void SetCounter(StatsCounter* counter, int value,
687 Register scratch1, Register scratch2);
688 void IncrementCounter(StatsCounter* counter, int value,
689 Register scratch1, Register scratch2);
690 void DecrementCounter(StatsCounter* counter, int value,
691 Register scratch1, Register scratch2);
692
693
694 // ---------------------------------------------------------------------------
695 // Debugging
696
697 // Calls Abort(msg) if the condition cc is not satisfied.
698 // Use --debug_code to enable.
699 void Assert(Condition cc, const char* msg);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100700 void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
Iain Merrick75681382010-08-19 15:07:18 +0100701 void AssertFastElements(Register elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000702
703 // Like Assert(), but always enabled.
704 void Check(Condition cc, const char* msg);
705
706 // Print a message to stdout and abort execution.
707 void Abort(const char* msg);
708
709 // Verify restrictions about code generated in stubs.
710 void set_generating_stub(bool value) { generating_stub_ = value; }
711 bool generating_stub() { return generating_stub_; }
712 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
713 bool allow_stub_calls() { return allow_stub_calls_; }
714
Leon Clarked91b9f72010-01-27 17:25:45 +0000715 // ---------------------------------------------------------------------------
Andrei Popescu31002712010-02-23 13:46:05 +0000716 // Smi utilities
717
Ben Murdochb0fe1622011-05-05 13:52:32 +0100718 void SmiTag(Register reg, SBit s = LeaveCC) {
719 add(reg, reg, Operand(reg), s);
720 }
721
Ben Murdochb8e0da22011-05-16 14:20:40 +0100722 // Try to convert int32 to smi. If the value is to large, preserve
723 // the original value and jump to not_a_smi. Destroys scratch and
724 // sets flags.
725 void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) {
726 mov(scratch, reg);
727 SmiTag(scratch, SetCC);
728 b(vs, not_a_smi);
729 mov(reg, scratch);
730 }
731
Ben Murdochb0fe1622011-05-05 13:52:32 +0100732 void SmiUntag(Register reg) {
733 mov(reg, Operand(reg, ASR, kSmiTagSize));
734 }
735
Andrei Popescu31002712010-02-23 13:46:05 +0000736 // Jump if either of the registers contain a non-smi.
737 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
738 // Jump if either of the registers contain a smi.
739 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
740
Iain Merrick75681382010-08-19 15:07:18 +0100741 // Abort execution if argument is a smi. Used in debug code.
742 void AbortIfSmi(Register object);
743
Andrei Popescu31002712010-02-23 13:46:05 +0000744 // ---------------------------------------------------------------------------
Leon Clarked91b9f72010-01-27 17:25:45 +0000745 // String utilities
746
747 // Checks if both objects are sequential ASCII strings and jumps to label
748 // if either is not. Assumes that neither object is a smi.
749 void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
750 Register object2,
751 Register scratch1,
752 Register scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100753 Label* failure);
Leon Clarked91b9f72010-01-27 17:25:45 +0000754
755 // Checks if both objects are sequential ASCII strings and jumps to label
756 // if either is not.
757 void JumpIfNotBothSequentialAsciiStrings(Register first,
758 Register second,
759 Register scratch1,
760 Register scratch2,
761 Label* not_flat_ascii_strings);
762
Steve Block6ded16b2010-05-10 14:33:55 +0100763 // Checks if both instance types are sequential ASCII strings and jumps to
764 // label if either is not.
765 void JumpIfBothInstanceTypesAreNotSequentialAscii(
766 Register first_object_instance_type,
767 Register second_object_instance_type,
768 Register scratch1,
769 Register scratch2,
770 Label* failure);
771
772 // Check if instance type is sequential ASCII string and jump to label if
773 // it is not.
774 void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
775 Register scratch,
776 Label* failure);
777
778
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 private:
Andrei Popescu31002712010-02-23 13:46:05 +0000780 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
781 void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000782
783 // Helper functions for generating invokes.
784 void InvokePrologue(const ParameterCount& expected,
785 const ParameterCount& actual,
786 Handle<Code> code_constant,
787 Register code_reg,
788 Label* done,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100789 InvokeFlag flag,
790 PostCallGenerator* post_call_generator = NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000791
Steve Blocka7e24c12009-10-30 11:49:00 +0000792 // Activation support.
793 void EnterFrame(StackFrame::Type type);
794 void LeaveFrame(StackFrame::Type type);
Andrei Popescu31002712010-02-23 13:46:05 +0000795
Steve Block6ded16b2010-05-10 14:33:55 +0100796 void InitializeNewString(Register string,
797 Register length,
798 Heap::RootListIndex map_index,
799 Register scratch1,
800 Register scratch2);
801
Andrei Popescu31002712010-02-23 13:46:05 +0000802 bool generating_stub_;
803 bool allow_stub_calls_;
804 // This handle will be patched with the code object on installation.
805 Handle<Object> code_object_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000806};
807
808
809#ifdef ENABLE_DEBUGGER_SUPPORT
810// The code patcher is used to patch (typically) small parts of code e.g. for
811// debugging and other types of instrumentation. When using the code patcher
812// the exact number of bytes specified must be emitted. It is not legal to emit
813// relocation information. If any of these constraints are violated it causes
814// an assertion to fail.
815class CodePatcher {
816 public:
817 CodePatcher(byte* address, int instructions);
818 virtual ~CodePatcher();
819
820 // Macro assembler to emit code.
821 MacroAssembler* masm() { return &masm_; }
822
823 // Emit an instruction directly.
824 void Emit(Instr x);
825
826 // Emit an address directly.
827 void Emit(Address addr);
828
829 private:
830 byte* address_; // The address of the code being patched.
831 int instructions_; // Number of instructions of the expected patch size.
832 int size_; // Number of bytes of the expected patch size.
833 MacroAssembler masm_; // Macro assembler used to generate the code.
834};
835#endif // ENABLE_DEBUGGER_SUPPORT
836
837
Ben Murdochb0fe1622011-05-05 13:52:32 +0100838// Helper class for generating code or data associated with the code
839// right after a call instruction. As an example this can be used to
840// generate safepoint data after calls for crankshaft.
841class PostCallGenerator {
842 public:
843 PostCallGenerator() { }
844 virtual ~PostCallGenerator() { }
845 virtual void Generate() = 0;
846};
847
848
Steve Blocka7e24c12009-10-30 11:49:00 +0000849// -----------------------------------------------------------------------------
850// Static helper functions.
851
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800852static MemOperand ContextOperand(Register context, int index) {
853 return MemOperand(context, Context::SlotOffset(index));
854}
855
856
857static inline MemOperand GlobalObjectOperand() {
858 return ContextOperand(cp, Context::GLOBAL_INDEX);
859}
860
861
Steve Blocka7e24c12009-10-30 11:49:00 +0000862#ifdef GENERATED_CODE_COVERAGE
863#define CODE_COVERAGE_STRINGIFY(x) #x
864#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
865#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
866#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
867#else
868#define ACCESS_MASM(masm) masm->
869#endif
870
871
872} } // namespace v8::internal
873
874#endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_