blob: 97bbb2fb678c86d50827b07260e2c100dcd4cd88 [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
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
Kristian Monsen25f61362010-05-21 11:50:48 +010055// Flags used for the AllocateInNewSpace functions.
56enum AllocationFlags {
57 // No special flags.
58 NO_ALLOCATION_FLAGS = 0,
59 // Return the pointer to the allocated already tagged as a heap object.
60 TAG_OBJECT = 1 << 0,
61 // The content of the result register already contains the allocation top in
62 // new space.
63 RESULT_CONTAINS_TOP = 1 << 1,
64 // Specify that the requested size of the space to allocate is specified in
65 // words instead of bytes.
66 SIZE_IN_WORDS = 1 << 2
67};
68
69
Steve Block8defd9f2010-07-08 12:39:36 +010070// Flags used for the ObjectToDoubleVFPRegister function.
71enum ObjectToDoubleFlags {
72 // No special flags.
73 NO_OBJECT_TO_DOUBLE_FLAGS = 0,
74 // Object is known to be a non smi.
75 OBJECT_NOT_SMI = 1 << 0,
76 // Don't load NaNs or infinities, branch to the non number case instead.
77 AVOID_NANS_AND_INFINITIES = 1 << 1
78};
79
80
Steve Blocka7e24c12009-10-30 11:49:00 +000081// MacroAssembler implements a collection of frequently used macros.
82class MacroAssembler: public Assembler {
83 public:
84 MacroAssembler(void* buffer, int size);
85
Andrei Popescu31002712010-02-23 13:46:05 +000086 // Jump, Call, and Ret pseudo instructions implementing inter-working.
Steve Blocka7e24c12009-10-30 11:49:00 +000087 void Jump(Register target, Condition cond = al);
88 void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
89 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
90 void Call(Register target, Condition cond = al);
91 void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
92 void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
93 void Ret(Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +000094
95 // Emit code to discard a non-negative number of pointer-sized elements
96 // from the stack, clobbering only the sp register.
97 void Drop(int count, Condition cond = al);
98
Ben Murdochb0fe1622011-05-05 13:52:32 +010099 void Ret(int drop, Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100100
101 // Swap two registers. If the scratch register is omitted then a slightly
102 // less efficient form using xor instead of mov is emitted.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100103 void Swap(Register reg1,
104 Register reg2,
105 Register scratch = no_reg,
106 Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100107
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100108
109 void And(Register dst, Register src1, const Operand& src2,
110 Condition cond = al);
111 void Ubfx(Register dst, Register src, int lsb, int width,
112 Condition cond = al);
113 void Sbfx(Register dst, Register src, int lsb, int width,
114 Condition cond = al);
115 void Bfc(Register dst, int lsb, int width, Condition cond = al);
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100116 void Usat(Register dst, int satpos, const Operand& src,
117 Condition cond = al);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100118
Leon Clarkee46be812010-01-19 14:06:41 +0000119 void Call(Label* target);
120 void Move(Register dst, Handle<Object> value);
Steve Block6ded16b2010-05-10 14:33:55 +0100121 // May do nothing if the registers are identical.
122 void Move(Register dst, Register src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 // Jumps to the label at the index given by the Smi in "index".
124 void SmiJumpTable(Register index, Vector<Label*> targets);
125 // Load an object from the root table.
126 void LoadRoot(Register destination,
127 Heap::RootListIndex index,
128 Condition cond = al);
Kristian Monsen25f61362010-05-21 11:50:48 +0100129 // Store an object to the root table.
130 void StoreRoot(Register source,
131 Heap::RootListIndex index,
132 Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000133
Steve Block6ded16b2010-05-10 14:33:55 +0100134
135 // Check if object is in new space.
136 // scratch can be object itself, but it will be clobbered.
137 void InNewSpace(Register object,
138 Register scratch,
139 Condition cc, // eq for new space, ne otherwise
140 Label* branch);
141
142
Steve Block8defd9f2010-07-08 12:39:36 +0100143 // For the page containing |object| mark the region covering [address]
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100144 // dirty. The object address must be in the first 8K of an allocated page.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100145 void RecordWriteHelper(Register object,
Steve Block8defd9f2010-07-08 12:39:36 +0100146 Register address,
147 Register scratch);
Steve Block6ded16b2010-05-10 14:33:55 +0100148
Steve Block8defd9f2010-07-08 12:39:36 +0100149 // For the page containing |object| mark the region covering
150 // [object+offset] dirty. The object address must be in the first 8K
151 // of an allocated page. The 'scratch' registers are used in the
152 // implementation and all 3 registers are clobbered by the
153 // operation, as well as the ip register. RecordWrite updates the
154 // write barrier even when storing smis.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100155 void RecordWrite(Register object,
156 Operand offset,
157 Register scratch0,
158 Register scratch1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000159
Steve Block8defd9f2010-07-08 12:39:36 +0100160 // For the page containing |object| mark the region covering
161 // [address] dirty. The object address must be in the first 8K of an
162 // allocated page. All 3 registers are clobbered by the operation,
163 // as well as the ip register. RecordWrite updates the write barrier
164 // even when storing smis.
165 void RecordWrite(Register object,
166 Register address,
167 Register scratch);
168
Steve Block6ded16b2010-05-10 14:33:55 +0100169 // Push two registers. Pushes leftmost register first (to highest address).
170 void Push(Register src1, Register src2, Condition cond = al) {
171 ASSERT(!src1.is(src2));
172 if (src1.code() > src2.code()) {
173 stm(db_w, sp, src1.bit() | src2.bit(), cond);
174 } else {
175 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
176 str(src2, MemOperand(sp, 4, NegPreIndex), cond);
177 }
178 }
179
180 // Push three registers. Pushes leftmost register first (to highest address).
181 void Push(Register src1, Register src2, Register src3, Condition cond = al) {
182 ASSERT(!src1.is(src2));
183 ASSERT(!src2.is(src3));
184 ASSERT(!src1.is(src3));
185 if (src1.code() > src2.code()) {
186 if (src2.code() > src3.code()) {
187 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
188 } else {
189 stm(db_w, sp, src1.bit() | src2.bit(), cond);
190 str(src3, MemOperand(sp, 4, NegPreIndex), cond);
191 }
192 } else {
193 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
194 Push(src2, src3, cond);
195 }
196 }
197
198 // Push four registers. Pushes leftmost register first (to highest address).
199 void Push(Register src1, Register src2,
200 Register src3, Register src4, Condition cond = al) {
201 ASSERT(!src1.is(src2));
202 ASSERT(!src2.is(src3));
203 ASSERT(!src1.is(src3));
204 ASSERT(!src1.is(src4));
205 ASSERT(!src2.is(src4));
206 ASSERT(!src3.is(src4));
207 if (src1.code() > src2.code()) {
208 if (src2.code() > src3.code()) {
209 if (src3.code() > src4.code()) {
210 stm(db_w,
211 sp,
212 src1.bit() | src2.bit() | src3.bit() | src4.bit(),
213 cond);
214 } else {
215 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
216 str(src4, MemOperand(sp, 4, NegPreIndex), cond);
217 }
218 } else {
219 stm(db_w, sp, src1.bit() | src2.bit(), cond);
220 Push(src3, src4, cond);
221 }
222 } else {
223 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
224 Push(src2, src3, src4, cond);
225 }
226 }
227
Ben Murdochb0fe1622011-05-05 13:52:32 +0100228 // Push and pop the registers that can hold pointers, as defined by the
229 // RegList constant kSafepointSavedRegisters.
230 void PushSafepointRegisters();
231 void PopSafepointRegisters();
232 static int SafepointRegisterStackIndex(int reg_code);
233
Leon Clarkef7060e22010-06-03 12:02:55 +0100234 // Load two consecutive registers with two consecutive memory locations.
235 void Ldrd(Register dst1,
236 Register dst2,
237 const MemOperand& src,
238 Condition cond = al);
239
240 // Store two consecutive registers to two consecutive memory locations.
241 void Strd(Register src1,
242 Register src2,
243 const MemOperand& dst,
244 Condition cond = al);
245
Steve Blocka7e24c12009-10-30 11:49:00 +0000246 // ---------------------------------------------------------------------------
247 // Activation frames
248
249 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
250 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
251
252 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
253 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
254
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100255 // Enter exit frame.
Steve Blockd0582a62009-12-15 09:54:21 +0000256 // Expects the number of arguments in register r0 and
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 // the builtin function to call in register r1. Exits with argc in
258 // r4, argv in r6, and and the builtin function to call in r5.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100259 void EnterExitFrame(bool save_doubles);
Steve Blocka7e24c12009-10-30 11:49:00 +0000260
261 // Leave the current exit frame. Expects the return value in r0.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100262 void LeaveExitFrame(bool save_doubles);
Steve Blocka7e24c12009-10-30 11:49:00 +0000263
Steve Block6ded16b2010-05-10 14:33:55 +0100264 // Get the actual activation frame alignment for target environment.
265 static int ActivationFrameAlignment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000266
Steve Blockd0582a62009-12-15 09:54:21 +0000267 void LoadContext(Register dst, int context_chain_length);
268
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800269 void LoadGlobalFunction(int index, Register function);
270
271 // Load the initial map from the global function. The registers
272 // function and map can be the same, function is then overwritten.
273 void LoadGlobalFunctionInitialMap(Register function,
274 Register map,
275 Register scratch);
276
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 // ---------------------------------------------------------------------------
278 // JavaScript invokes
279
280 // Invoke the JavaScript function code by either calling or jumping.
281 void InvokeCode(Register code,
282 const ParameterCount& expected,
283 const ParameterCount& actual,
284 InvokeFlag flag);
285
286 void InvokeCode(Handle<Code> code,
287 const ParameterCount& expected,
288 const ParameterCount& actual,
289 RelocInfo::Mode rmode,
290 InvokeFlag flag);
291
292 // Invoke the JavaScript function in the given register. Changes the
293 // current context to the context in the function before invoking.
294 void InvokeFunction(Register function,
295 const ParameterCount& actual,
296 InvokeFlag flag);
297
Andrei Popescu402d9372010-02-26 13:31:12 +0000298 void InvokeFunction(JSFunction* function,
299 const ParameterCount& actual,
300 InvokeFlag flag);
301
Ben Murdochb0fe1622011-05-05 13:52:32 +0100302 void IsObjectJSObjectType(Register heap_object,
303 Register map,
304 Register scratch,
305 Label* fail);
306
307 void IsInstanceJSObjectType(Register map,
308 Register scratch,
309 Label* fail);
310
311 void IsObjectJSStringType(Register object,
312 Register scratch,
313 Label* fail);
Steve Blocka7e24c12009-10-30 11:49:00 +0000314
315#ifdef ENABLE_DEBUGGER_SUPPORT
316 // ---------------------------------------------------------------------------
317 // Debugger Support
318
Andrei Popescu402d9372010-02-26 13:31:12 +0000319 void DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +0000320#endif
321
322 // ---------------------------------------------------------------------------
323 // Exception handling
324
325 // Push a new try handler and link into try handler chain.
326 // The return address must be passed in register lr.
327 // On exit, r0 contains TOS (code slot).
328 void PushTryHandler(CodeLocation try_location, HandlerType type);
329
Leon Clarkee46be812010-01-19 14:06:41 +0000330 // Unlink the stack handler on top of the stack from the try handler chain.
331 // Must preserve the result register.
332 void PopTryHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000333
334 // ---------------------------------------------------------------------------
335 // Inline caching support
336
Steve Blocka7e24c12009-10-30 11:49:00 +0000337 // Generate code for checking access rights - used for security checks
338 // on access to global objects across environments. The holder register
339 // is left untouched, whereas both scratch registers are clobbered.
340 void CheckAccessGlobalProxy(Register holder_reg,
341 Register scratch,
342 Label* miss);
343
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800344 inline void MarkCode(NopMarkerTypes type) {
345 nop(type);
346 }
347
348 // Check if the given instruction is a 'type' marker.
349 // ie. check if is is a mov r<type>, r<type> (referenced as nop(type))
350 // These instructions are generated to mark special location in the code,
351 // like some special IC code.
352 static inline bool IsMarkedCode(Instr instr, int type) {
353 ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
354 return IsNop(instr, type);
355 }
356
357
358 static inline int GetCodeMarker(Instr instr) {
359 int dst_reg_offset = 12;
360 int dst_mask = 0xf << dst_reg_offset;
361 int src_mask = 0xf;
362 int dst_reg = (instr & dst_mask) >> dst_reg_offset;
363 int src_reg = instr & src_mask;
364 uint32_t non_register_mask = ~(dst_mask | src_mask);
365 uint32_t mov_mask = al | 13 << 21;
366
367 // Return <n> if we have a mov rn rn, else return -1.
368 int type = ((instr & non_register_mask) == mov_mask) &&
369 (dst_reg == src_reg) &&
370 (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER)
371 ? src_reg
372 : -1;
373 ASSERT((type == -1) ||
374 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
375 return type;
376 }
377
Steve Blocka7e24c12009-10-30 11:49:00 +0000378
379 // ---------------------------------------------------------------------------
380 // Allocation support
381
382 // Allocate an object in new space. The object_size is specified in words (not
383 // bytes). If the new space is exhausted control continues at the gc_required
384 // label. The allocated object is returned in result. If the flag
Kristian Monsen25f61362010-05-21 11:50:48 +0100385 // tag_allocated_object is true the result is tagged as as a heap object. All
386 // registers are clobbered also when control continues at the gc_required
387 // label.
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 void AllocateInNewSpace(int object_size,
389 Register result,
390 Register scratch1,
391 Register scratch2,
392 Label* gc_required,
393 AllocationFlags flags);
394 void AllocateInNewSpace(Register object_size,
395 Register result,
396 Register scratch1,
397 Register scratch2,
398 Label* gc_required,
399 AllocationFlags flags);
400
401 // Undo allocation in new space. The object passed and objects allocated after
402 // it will no longer be allocated. The caller must make sure that no pointers
403 // are left to the object(s) no longer allocated as they would be invalid when
404 // allocation is undone.
405 void UndoAllocationInNewSpace(Register object, Register scratch);
406
Andrei Popescu31002712010-02-23 13:46:05 +0000407
408 void AllocateTwoByteString(Register result,
409 Register length,
410 Register scratch1,
411 Register scratch2,
412 Register scratch3,
413 Label* gc_required);
414 void AllocateAsciiString(Register result,
415 Register length,
416 Register scratch1,
417 Register scratch2,
418 Register scratch3,
419 Label* gc_required);
420 void AllocateTwoByteConsString(Register result,
421 Register length,
422 Register scratch1,
423 Register scratch2,
424 Label* gc_required);
425 void AllocateAsciiConsString(Register result,
426 Register length,
427 Register scratch1,
428 Register scratch2,
429 Label* gc_required);
430
Kristian Monsen25f61362010-05-21 11:50:48 +0100431 // Allocates a heap number or jumps to the gc_required label if the young
432 // space is full and a scavenge is needed. All registers are clobbered also
433 // when control continues at the gc_required label.
Steve Block6ded16b2010-05-10 14:33:55 +0100434 void AllocateHeapNumber(Register result,
435 Register scratch1,
436 Register scratch2,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100437 Register heap_number_map,
Steve Block6ded16b2010-05-10 14:33:55 +0100438 Label* gc_required);
Steve Block8defd9f2010-07-08 12:39:36 +0100439 void AllocateHeapNumberWithValue(Register result,
440 DwVfpRegister value,
441 Register scratch1,
442 Register scratch2,
443 Register heap_number_map,
444 Label* gc_required);
445
Ben Murdochbb769b22010-08-11 14:56:33 +0100446 // Copies a fixed number of fields of heap objects from src to dst.
447 void CopyFields(Register dst, Register src, RegList temps, int field_count);
Andrei Popescu31002712010-02-23 13:46:05 +0000448
Steve Blocka7e24c12009-10-30 11:49:00 +0000449 // ---------------------------------------------------------------------------
450 // Support functions.
451
452 // Try to get function prototype of a function and puts the value in
453 // the result register. Checks that the function really is a
454 // function and jumps to the miss label if the fast checks fail. The
455 // function register will be untouched; the other registers may be
456 // clobbered.
457 void TryGetFunctionPrototype(Register function,
458 Register result,
459 Register scratch,
460 Label* miss);
461
462 // Compare object type for heap object. heap_object contains a non-Smi
463 // whose object type should be compared with the given type. This both
464 // sets the flags and leaves the object type in the type_reg register.
465 // It leaves the map in the map register (unless the type_reg and map register
466 // are the same register). It leaves the heap object in the heap_object
467 // register unless the heap_object register is the same register as one of the
468 // other registers.
469 void CompareObjectType(Register heap_object,
470 Register map,
471 Register type_reg,
472 InstanceType type);
473
474 // Compare instance type in a map. map contains a valid map object whose
475 // object type should be compared with the given type. This both
476 // sets the flags and leaves the object type in the type_reg register. It
477 // leaves the heap object in the heap_object register unless the heap_object
478 // register is the same register as type_reg.
479 void CompareInstanceType(Register map,
480 Register type_reg,
481 InstanceType type);
482
Andrei Popescu31002712010-02-23 13:46:05 +0000483
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100484 // Check if the map of an object is equal to a specified map (either
485 // given directly or as an index into the root list) and branch to
486 // label if not. Skip the smi check if not required (object is known
487 // to be a heap object)
Andrei Popescu31002712010-02-23 13:46:05 +0000488 void CheckMap(Register obj,
489 Register scratch,
490 Handle<Map> map,
491 Label* fail,
492 bool is_heap_object);
493
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100494 void CheckMap(Register obj,
495 Register scratch,
496 Heap::RootListIndex index,
497 Label* fail,
498 bool is_heap_object);
499
500
Andrei Popescu31002712010-02-23 13:46:05 +0000501 // Load and check the instance type of an object for being a string.
502 // Loads the type into the second argument register.
503 // Returns a condition that will be enabled if the object was a string.
504 Condition IsObjectStringType(Register obj,
505 Register type) {
506 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
507 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
508 tst(type, Operand(kIsNotStringMask));
509 ASSERT_EQ(0, kStringTag);
510 return eq;
511 }
512
513
Steve Blocka7e24c12009-10-30 11:49:00 +0000514 inline void BranchOnSmi(Register value, Label* smi_label) {
515 tst(value, Operand(kSmiTagMask));
516 b(eq, smi_label);
517 }
518
519 inline void BranchOnNotSmi(Register value, Label* not_smi_label) {
520 tst(value, Operand(kSmiTagMask));
521 b(ne, not_smi_label);
522 }
523
524 // Generates code for reporting that an illegal operation has
525 // occurred.
526 void IllegalOperation(int num_arguments);
527
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100528 // Picks out an array index from the hash field.
529 // Register use:
530 // hash - holds the index's hash. Clobbered.
531 // index - holds the overwritten index on exit.
532 void IndexFromHash(Register hash, Register index);
533
Andrei Popescu31002712010-02-23 13:46:05 +0000534 // Get the number of least significant bits from a register
535 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
536
Steve Blockd0582a62009-12-15 09:54:21 +0000537 // Uses VFP instructions to Convert a Smi to a double.
538 void IntegerToDoubleConversionWithVFP3(Register inReg,
539 Register outHighReg,
540 Register outLowReg);
541
Steve Block8defd9f2010-07-08 12:39:36 +0100542 // Load the value of a number object into a VFP double register. If the object
543 // is not a number a jump to the label not_number is performed and the VFP
544 // double register is unchanged.
545 void ObjectToDoubleVFPRegister(
546 Register object,
547 DwVfpRegister value,
548 Register scratch1,
549 Register scratch2,
550 Register heap_number_map,
551 SwVfpRegister scratch3,
552 Label* not_number,
553 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS);
554
555 // Load the value of a smi object into a VFP double register. The register
556 // scratch1 can be the same register as smi in which case smi will hold the
557 // untagged value afterwards.
558 void SmiToDoubleVFPRegister(Register smi,
559 DwVfpRegister value,
560 Register scratch1,
561 SwVfpRegister scratch2);
562
Iain Merrick9ac36c92010-09-13 15:29:50 +0100563 // Convert the HeapNumber pointed to by source to a 32bits signed integer
564 // dest. If the HeapNumber does not fit into a 32bits signed integer branch
565 // to not_int32 label.
566 void ConvertToInt32(Register source,
567 Register dest,
568 Register scratch,
569 Register scratch2,
570 Label *not_int32);
571
Steve Block6ded16b2010-05-10 14:33:55 +0100572 // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
573 // instruction. On pre-ARM5 hardware this routine gives the wrong answer
Steve Block8defd9f2010-07-08 12:39:36 +0100574 // for 0 (31 instead of 32). Source and scratch can be the same in which case
575 // the source is clobbered. Source and zeros can also be the same in which
576 // case scratch should be a different register.
577 void CountLeadingZeros(Register zeros,
578 Register source,
579 Register scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000580
581 // ---------------------------------------------------------------------------
582 // Runtime calls
583
584 // Call a code stub.
585 void CallStub(CodeStub* stub, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000586
Andrei Popescu31002712010-02-23 13:46:05 +0000587 // Call a code stub.
588 void TailCallStub(CodeStub* stub, Condition cond = al);
589
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 // Call a runtime routine.
Steve Blocka7e24c12009-10-30 11:49:00 +0000591 void CallRuntime(Runtime::Function* f, int num_arguments);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100592 void CallRuntimeSaveDoubles(Runtime::FunctionId id);
Steve Blocka7e24c12009-10-30 11:49:00 +0000593
594 // Convenience function: Same as above, but takes the fid instead.
595 void CallRuntime(Runtime::FunctionId fid, int num_arguments);
596
Andrei Popescu402d9372010-02-26 13:31:12 +0000597 // Convenience function: call an external reference.
598 void CallExternalReference(const ExternalReference& ext,
599 int num_arguments);
600
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 // Tail call of a runtime routine (jump).
Steve Block6ded16b2010-05-10 14:33:55 +0100602 // Like JumpToExternalReference, but also takes care of passing the number
Steve Blocka7e24c12009-10-30 11:49:00 +0000603 // of parameters.
Steve Block6ded16b2010-05-10 14:33:55 +0100604 void TailCallExternalReference(const ExternalReference& ext,
605 int num_arguments,
606 int result_size);
607
608 // Convenience function: tail call a runtime routine (jump).
609 void TailCallRuntime(Runtime::FunctionId fid,
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 int num_arguments,
611 int result_size);
612
Steve Block6ded16b2010-05-10 14:33:55 +0100613 // Before calling a C-function from generated code, align arguments on stack.
614 // After aligning the frame, non-register arguments must be stored in
615 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
616 // are word sized.
617 // Some compilers/platforms require the stack to be aligned when calling
618 // C++ code.
619 // Needs a scratch register to do some arithmetic. This register will be
620 // trashed.
621 void PrepareCallCFunction(int num_arguments, Register scratch);
622
623 // Calls a C function and cleans up the space for arguments allocated
624 // by PrepareCallCFunction. The called function is not allowed to trigger a
625 // garbage collection, since that might move the code and invalidate the
626 // return address (unless this is somehow accounted for by the called
627 // function).
628 void CallCFunction(ExternalReference function, int num_arguments);
629 void CallCFunction(Register function, int num_arguments);
630
Steve Blocka7e24c12009-10-30 11:49:00 +0000631 // Jump to a runtime routine.
Steve Block6ded16b2010-05-10 14:33:55 +0100632 void JumpToExternalReference(const ExternalReference& builtin);
Steve Blocka7e24c12009-10-30 11:49:00 +0000633
634 // Invoke specified builtin JavaScript function. Adds an entry to
635 // the unresolved list if the name does not resolve.
636 void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
637
638 // Store the code object for the given builtin in the target register and
639 // setup the function in r1.
640 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
641
Steve Block791712a2010-08-27 10:21:07 +0100642 // Store the function for the given builtin in the target register.
643 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
644
Steve Blocka7e24c12009-10-30 11:49:00 +0000645 Handle<Object> CodeObject() { return code_object_; }
646
647
648 // ---------------------------------------------------------------------------
649 // StatsCounter support
650
651 void SetCounter(StatsCounter* counter, int value,
652 Register scratch1, Register scratch2);
653 void IncrementCounter(StatsCounter* counter, int value,
654 Register scratch1, Register scratch2);
655 void DecrementCounter(StatsCounter* counter, int value,
656 Register scratch1, Register scratch2);
657
658
659 // ---------------------------------------------------------------------------
660 // Debugging
661
662 // Calls Abort(msg) if the condition cc is not satisfied.
663 // Use --debug_code to enable.
664 void Assert(Condition cc, const char* msg);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100665 void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
Iain Merrick75681382010-08-19 15:07:18 +0100666 void AssertFastElements(Register elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000667
668 // Like Assert(), but always enabled.
669 void Check(Condition cc, const char* msg);
670
671 // Print a message to stdout and abort execution.
672 void Abort(const char* msg);
673
674 // Verify restrictions about code generated in stubs.
675 void set_generating_stub(bool value) { generating_stub_ = value; }
676 bool generating_stub() { return generating_stub_; }
677 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
678 bool allow_stub_calls() { return allow_stub_calls_; }
679
Leon Clarked91b9f72010-01-27 17:25:45 +0000680 // ---------------------------------------------------------------------------
Andrei Popescu31002712010-02-23 13:46:05 +0000681 // Smi utilities
682
Ben Murdochb0fe1622011-05-05 13:52:32 +0100683 void SmiTag(Register reg, SBit s = LeaveCC) {
684 add(reg, reg, Operand(reg), s);
685 }
686
687 void SmiUntag(Register reg) {
688 mov(reg, Operand(reg, ASR, kSmiTagSize));
689 }
690
Andrei Popescu31002712010-02-23 13:46:05 +0000691 // Jump if either of the registers contain a non-smi.
692 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
693 // Jump if either of the registers contain a smi.
694 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
695
Iain Merrick75681382010-08-19 15:07:18 +0100696 // Abort execution if argument is a smi. Used in debug code.
697 void AbortIfSmi(Register object);
698
Andrei Popescu31002712010-02-23 13:46:05 +0000699 // ---------------------------------------------------------------------------
Leon Clarked91b9f72010-01-27 17:25:45 +0000700 // String utilities
701
702 // Checks if both objects are sequential ASCII strings and jumps to label
703 // if either is not. Assumes that neither object is a smi.
704 void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
705 Register object2,
706 Register scratch1,
707 Register scratch2,
Steve Block6ded16b2010-05-10 14:33:55 +0100708 Label* failure);
Leon Clarked91b9f72010-01-27 17:25:45 +0000709
710 // Checks if both objects are sequential ASCII strings and jumps to label
711 // if either is not.
712 void JumpIfNotBothSequentialAsciiStrings(Register first,
713 Register second,
714 Register scratch1,
715 Register scratch2,
716 Label* not_flat_ascii_strings);
717
Steve Block6ded16b2010-05-10 14:33:55 +0100718 // Checks if both instance types are sequential ASCII strings and jumps to
719 // label if either is not.
720 void JumpIfBothInstanceTypesAreNotSequentialAscii(
721 Register first_object_instance_type,
722 Register second_object_instance_type,
723 Register scratch1,
724 Register scratch2,
725 Label* failure);
726
727 // Check if instance type is sequential ASCII string and jump to label if
728 // it is not.
729 void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
730 Register scratch,
731 Label* failure);
732
733
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 private:
Andrei Popescu31002712010-02-23 13:46:05 +0000735 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
736 void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000737
738 // Helper functions for generating invokes.
739 void InvokePrologue(const ParameterCount& expected,
740 const ParameterCount& actual,
741 Handle<Code> code_constant,
742 Register code_reg,
743 Label* done,
744 InvokeFlag flag);
745
Steve Blocka7e24c12009-10-30 11:49:00 +0000746 // Activation support.
747 void EnterFrame(StackFrame::Type type);
748 void LeaveFrame(StackFrame::Type type);
Andrei Popescu31002712010-02-23 13:46:05 +0000749
Steve Block6ded16b2010-05-10 14:33:55 +0100750 void InitializeNewString(Register string,
751 Register length,
752 Heap::RootListIndex map_index,
753 Register scratch1,
754 Register scratch2);
755
Andrei Popescu31002712010-02-23 13:46:05 +0000756 bool generating_stub_;
757 bool allow_stub_calls_;
758 // This handle will be patched with the code object on installation.
759 Handle<Object> code_object_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000760};
761
762
763#ifdef ENABLE_DEBUGGER_SUPPORT
764// The code patcher is used to patch (typically) small parts of code e.g. for
765// debugging and other types of instrumentation. When using the code patcher
766// the exact number of bytes specified must be emitted. It is not legal to emit
767// relocation information. If any of these constraints are violated it causes
768// an assertion to fail.
769class CodePatcher {
770 public:
771 CodePatcher(byte* address, int instructions);
772 virtual ~CodePatcher();
773
774 // Macro assembler to emit code.
775 MacroAssembler* masm() { return &masm_; }
776
777 // Emit an instruction directly.
778 void Emit(Instr x);
779
780 // Emit an address directly.
781 void Emit(Address addr);
782
783 private:
784 byte* address_; // The address of the code being patched.
785 int instructions_; // Number of instructions of the expected patch size.
786 int size_; // Number of bytes of the expected patch size.
787 MacroAssembler masm_; // Macro assembler used to generate the code.
788};
789#endif // ENABLE_DEBUGGER_SUPPORT
790
791
Ben Murdochb0fe1622011-05-05 13:52:32 +0100792// Helper class for generating code or data associated with the code
793// right after a call instruction. As an example this can be used to
794// generate safepoint data after calls for crankshaft.
795class PostCallGenerator {
796 public:
797 PostCallGenerator() { }
798 virtual ~PostCallGenerator() { }
799 virtual void Generate() = 0;
800};
801
802
Steve Blocka7e24c12009-10-30 11:49:00 +0000803// -----------------------------------------------------------------------------
804// Static helper functions.
805
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800806static MemOperand ContextOperand(Register context, int index) {
807 return MemOperand(context, Context::SlotOffset(index));
808}
809
810
811static inline MemOperand GlobalObjectOperand() {
812 return ContextOperand(cp, Context::GLOBAL_INDEX);
813}
814
815
Steve Blocka7e24c12009-10-30 11:49:00 +0000816#ifdef GENERATED_CODE_COVERAGE
817#define CODE_COVERAGE_STRINGIFY(x) #x
818#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
819#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
820#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
821#else
822#define ACCESS_MASM(masm) masm->
823#endif
824
825
826} } // namespace v8::internal
827
828#endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_