blob: 0802d7ca6fc2c7539b55660e81482d54163f2ca8 [file] [log] [blame]
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
ager@chromium.org5ec48922009-05-05 07:25:34 +000028#ifndef V8_ARM_MACRO_ASSEMBLER_ARM_H_
29#define V8_ARM_MACRO_ASSEMBLER_ARM_H_
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
31#include "assembler.h"
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000032#include "v8globals.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
ager@chromium.org5c838252010-02-19 08:53:10 +000037// ----------------------------------------------------------------------------
38// Static helper functions
39
40// Generate a MemOperand for loading a field from an object.
41static inline MemOperand FieldMemOperand(Register object, int offset) {
42 return MemOperand(object, offset - kHeapObjectTag);
43}
44
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000046static inline Operand SmiUntagOperand(Register object) {
47 return Operand(object, ASR, kSmiTagSize);
48}
49
50
51
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052// Give alias names to registers
ager@chromium.orgeadaf222009-06-16 09:43:10 +000053const Register cp = { 8 }; // JavaScript context pointer
ager@chromium.org5c838252010-02-19 08:53:10 +000054const Register roots = { 10 }; // Roots array pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000056// Flags used for the AllocateInNewSpace functions.
57enum AllocationFlags {
58 // No special flags.
59 NO_ALLOCATION_FLAGS = 0,
60 // Return the pointer to the allocated already tagged as a heap object.
61 TAG_OBJECT = 1 << 0,
62 // The content of the result register already contains the allocation top in
63 // new space.
64 RESULT_CONTAINS_TOP = 1 << 1,
65 // Specify that the requested size of the space to allocate is specified in
66 // words instead of bytes.
67 SIZE_IN_WORDS = 1 << 2
68};
69
70
lrn@chromium.org32d961d2010-06-30 09:09:34 +000071// Flags used for the ObjectToDoubleVFPRegister function.
72enum ObjectToDoubleFlags {
73 // No special flags.
74 NO_OBJECT_TO_DOUBLE_FLAGS = 0,
75 // Object is known to be a non smi.
76 OBJECT_NOT_SMI = 1 << 0,
77 // Don't load NaNs or infinities, branch to the non number case instead.
78 AVOID_NANS_AND_INFINITIES = 1 << 1
79};
80
81
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082// MacroAssembler implements a collection of frequently used macros.
83class MacroAssembler: public Assembler {
84 public:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000085 // The isolate parameter can be NULL if the macro assembler should
86 // not use isolate-dependent functionality. In this case, it's the
87 // responsibility of the caller to never invoke such function on the
88 // macro assembler.
89 MacroAssembler(Isolate* isolate, void* buffer, int size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090
ager@chromium.org5c838252010-02-19 08:53:10 +000091 // Jump, Call, and Ret pseudo instructions implementing inter-working.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092 void Jump(Register target, Condition cond = al);
ager@chromium.org236ad962008-09-25 09:45:57 +000093 void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
94 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000095 int CallSize(Register target, Condition cond = al);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 void Call(Register target, Condition cond = al);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000097 int CallSize(byte* target, RelocInfo::Mode rmode, Condition cond = al);
ager@chromium.org236ad962008-09-25 09:45:57 +000098 void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000099 int CallSize(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000100 void Call(Handle<Code> code,
101 RelocInfo::Mode rmode,
102 Condition cond = al);
103 void CallWithAstId(Handle<Code> code,
104 RelocInfo::Mode rmode,
105 unsigned ast_id,
106 Condition cond = al);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000107 void Ret(Condition cond = al);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000108
109 // Emit code to discard a non-negative number of pointer-sized elements
110 // from the stack, clobbering only the sp register.
111 void Drop(int count, Condition cond = al);
112
whesse@chromium.org023421e2010-12-21 12:19:12 +0000113 void Ret(int drop, Condition cond = al);
ager@chromium.org357bf652010-04-12 11:30:10 +0000114
115 // Swap two registers. If the scratch register is omitted then a slightly
116 // less efficient form using xor instead of mov is emitted.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000117 void Swap(Register reg1,
118 Register reg2,
119 Register scratch = no_reg,
120 Condition cond = al);
ager@chromium.org357bf652010-04-12 11:30:10 +0000121
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000122
123 void And(Register dst, Register src1, const Operand& src2,
124 Condition cond = al);
125 void Ubfx(Register dst, Register src, int lsb, int width,
126 Condition cond = al);
127 void Sbfx(Register dst, Register src, int lsb, int width,
128 Condition cond = al);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000129 // The scratch register is not used for ARMv7.
130 // scratch can be the same register as src (in which case it is trashed), but
131 // not the same as dst.
132 void Bfi(Register dst,
133 Register src,
134 Register scratch,
135 int lsb,
136 int width,
137 Condition cond = al);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000138 void Bfc(Register dst, int lsb, int width, Condition cond = al);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000139 void Usat(Register dst, int satpos, const Operand& src,
140 Condition cond = al);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000141
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000142 void Call(Label* target);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000143
144 // Register move. May do nothing if the registers are identical.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000145 void Move(Register dst, Handle<Object> value);
ager@chromium.org357bf652010-04-12 11:30:10 +0000146 void Move(Register dst, Register src);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000147 void Move(DoubleRegister dst, DoubleRegister src);
148
ager@chromium.org8bb60582008-12-11 12:02:20 +0000149 // Jumps to the label at the index given by the Smi in "index".
150 void SmiJumpTable(Register index, Vector<Label*> targets);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000151 // Load an object from the root table.
152 void LoadRoot(Register destination,
153 Heap::RootListIndex index,
154 Condition cond = al);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000155 // Store an object to the root table.
156 void StoreRoot(Register source,
157 Heap::RootListIndex index,
158 Condition cond = al);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000159
ager@chromium.orgac091b72010-05-05 07:34:42 +0000160
161 // Check if object is in new space.
162 // scratch can be object itself, but it will be clobbered.
163 void InNewSpace(Register object,
164 Register scratch,
ager@chromium.org378b34e2011-01-28 08:04:38 +0000165 Condition cond, // eq for new space, ne otherwise
ager@chromium.orgac091b72010-05-05 07:34:42 +0000166 Label* branch);
167
168
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000169 // For the page containing |object| mark the region covering [address]
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000170 // dirty. The object address must be in the first 8K of an allocated page.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000171 void RecordWriteHelper(Register object,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000172 Register address,
173 Register scratch);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000174
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000175 // For the page containing |object| mark the region covering
176 // [object+offset] dirty. The object address must be in the first 8K
177 // of an allocated page. The 'scratch' registers are used in the
178 // implementation and all 3 registers are clobbered by the
179 // operation, as well as the ip register. RecordWrite updates the
180 // write barrier even when storing smis.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000181 void RecordWrite(Register object,
182 Operand offset,
183 Register scratch0,
184 Register scratch1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000186 // For the page containing |object| mark the region covering
187 // [address] dirty. The object address must be in the first 8K of an
188 // allocated page. All 3 registers are clobbered by the operation,
189 // as well as the ip register. RecordWrite updates the write barrier
190 // even when storing smis.
191 void RecordWrite(Register object,
192 Register address,
193 Register scratch);
194
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000195 // Push a handle.
196 void Push(Handle<Object> handle);
197
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000198 // Push two registers. Pushes leftmost register first (to highest address).
199 void Push(Register src1, Register src2, Condition cond = al) {
200 ASSERT(!src1.is(src2));
201 if (src1.code() > src2.code()) {
202 stm(db_w, sp, src1.bit() | src2.bit(), cond);
203 } else {
204 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
205 str(src2, MemOperand(sp, 4, NegPreIndex), cond);
206 }
207 }
208
209 // Push three registers. Pushes leftmost register first (to highest address).
210 void Push(Register src1, Register src2, Register src3, Condition cond = al) {
211 ASSERT(!src1.is(src2));
212 ASSERT(!src2.is(src3));
213 ASSERT(!src1.is(src3));
214 if (src1.code() > src2.code()) {
215 if (src2.code() > src3.code()) {
216 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
217 } else {
218 stm(db_w, sp, src1.bit() | src2.bit(), cond);
219 str(src3, MemOperand(sp, 4, NegPreIndex), cond);
220 }
221 } else {
222 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
223 Push(src2, src3, cond);
224 }
225 }
226
227 // Push four registers. Pushes leftmost register first (to highest address).
228 void Push(Register src1, Register src2,
229 Register src3, Register src4, Condition cond = al) {
230 ASSERT(!src1.is(src2));
231 ASSERT(!src2.is(src3));
232 ASSERT(!src1.is(src3));
233 ASSERT(!src1.is(src4));
234 ASSERT(!src2.is(src4));
235 ASSERT(!src3.is(src4));
236 if (src1.code() > src2.code()) {
237 if (src2.code() > src3.code()) {
238 if (src3.code() > src4.code()) {
239 stm(db_w,
240 sp,
241 src1.bit() | src2.bit() | src3.bit() | src4.bit(),
242 cond);
243 } else {
244 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
245 str(src4, MemOperand(sp, 4, NegPreIndex), cond);
246 }
247 } else {
248 stm(db_w, sp, src1.bit() | src2.bit(), cond);
249 Push(src3, src4, cond);
250 }
251 } else {
252 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
253 Push(src2, src3, src4, cond);
254 }
255 }
256
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000257 // Pop two registers. Pops rightmost register first (from lower address).
258 void Pop(Register src1, Register src2, Condition cond = al) {
259 ASSERT(!src1.is(src2));
260 if (src1.code() > src2.code()) {
261 ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
262 } else {
263 ldr(src2, MemOperand(sp, 4, PostIndex), cond);
264 ldr(src1, MemOperand(sp, 4, PostIndex), cond);
265 }
266 }
267
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000268 // Push and pop the registers that can hold pointers, as defined by the
269 // RegList constant kSafepointSavedRegisters.
270 void PushSafepointRegisters();
271 void PopSafepointRegisters();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000272 void PushSafepointRegistersAndDoubles();
273 void PopSafepointRegistersAndDoubles();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000274 // Store value in register src in the safepoint stack slot for
275 // register dst.
276 void StoreToSafepointRegisterSlot(Register src, Register dst);
277 void StoreToSafepointRegistersAndDoublesSlot(Register src, Register dst);
278 // Load the value of the src register from its safepoint stack slot
279 // into register dst.
280 void LoadFromSafepointRegisterSlot(Register dst, Register src);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000281
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000282 // Load two consecutive registers with two consecutive memory locations.
283 void Ldrd(Register dst1,
284 Register dst2,
285 const MemOperand& src,
286 Condition cond = al);
287
288 // Store two consecutive registers to two consecutive memory locations.
289 void Strd(Register src1,
290 Register src2,
291 const MemOperand& dst,
292 Condition cond = al);
293
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000294 // Clear specified FPSCR bits.
295 void ClearFPSCRBits(const uint32_t bits_to_clear,
296 const Register scratch,
297 const Condition cond = al);
298
299 // Compare double values and move the result to the normal condition flags.
300 void VFPCompareAndSetFlags(const DwVfpRegister src1,
301 const DwVfpRegister src2,
302 const Condition cond = al);
303 void VFPCompareAndSetFlags(const DwVfpRegister src1,
304 const double src2,
305 const Condition cond = al);
306
307 // Compare double values and then load the fpscr flags to a register.
308 void VFPCompareAndLoadFlags(const DwVfpRegister src1,
309 const DwVfpRegister src2,
310 const Register fpscr_flags,
311 const Condition cond = al);
312 void VFPCompareAndLoadFlags(const DwVfpRegister src1,
313 const double src2,
314 const Register fpscr_flags,
315 const Condition cond = al);
316
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 // ---------------------------------------------------------------------------
319 // Activation frames
320
ager@chromium.org7c537e22008-10-16 08:43:32 +0000321 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
322 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
323
324 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
325 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
ager@chromium.org236ad962008-09-25 09:45:57 +0000326
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000327 // Enter exit frame.
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000328 // stack_space - extra stack space, used for alignment before call to C.
329 void EnterExitFrame(bool save_doubles, int stack_space = 0);
ager@chromium.org236ad962008-09-25 09:45:57 +0000330
331 // Leave the current exit frame. Expects the return value in r0.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000332 // Expect the number of values, pushed prior to the exit frame, to
333 // remove in a register (or no_reg, if there is nothing to remove).
334 void LeaveExitFrame(bool save_doubles, Register argument_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000336 // Get the actual activation frame alignment for target environment.
337 static int ActivationFrameAlignment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000339 void LoadContext(Register dst, int context_chain_length);
340
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000341 void LoadGlobalFunction(int index, Register function);
342
343 // Load the initial map from the global function. The registers
344 // function and map can be the same, function is then overwritten.
345 void LoadGlobalFunctionInitialMap(Register function,
346 Register map,
347 Register scratch);
348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 // ---------------------------------------------------------------------------
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000350 // JavaScript invokes
351
danno@chromium.org40cb8782011-05-25 07:58:50 +0000352 // Setup call kind marking in ecx. The method takes ecx as an
353 // explicit first parameter to make the code more readable at the
354 // call sites.
355 void SetCallKind(Register dst, CallKind kind);
356
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000357 // Invoke the JavaScript function code by either calling or jumping.
358 void InvokeCode(Register code,
359 const ParameterCount& expected,
360 const ParameterCount& actual,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000361 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000362 const CallWrapper& call_wrapper,
363 CallKind call_kind);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000364
365 void InvokeCode(Handle<Code> code,
366 const ParameterCount& expected,
367 const ParameterCount& actual,
ager@chromium.org236ad962008-09-25 09:45:57 +0000368 RelocInfo::Mode rmode,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000369 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000370 CallKind call_kind);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000371
372 // Invoke the JavaScript function in the given register. Changes the
373 // current context to the context in the function before invoking.
374 void InvokeFunction(Register function,
375 const ParameterCount& actual,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000376 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000377 const CallWrapper& call_wrapper,
378 CallKind call_kind);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000379
ager@chromium.org5c838252010-02-19 08:53:10 +0000380 void InvokeFunction(JSFunction* function,
381 const ParameterCount& actual,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000382 InvokeFlag flag,
383 CallKind call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000384
whesse@chromium.org023421e2010-12-21 12:19:12 +0000385 void IsObjectJSObjectType(Register heap_object,
386 Register map,
387 Register scratch,
388 Label* fail);
389
390 void IsInstanceJSObjectType(Register map,
391 Register scratch,
392 Label* fail);
393
394 void IsObjectJSStringType(Register object,
395 Register scratch,
396 Label* fail);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000397
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000398#ifdef ENABLE_DEBUGGER_SUPPORT
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000399 // ---------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 // Debugger Support
401
ager@chromium.org5c838252010-02-19 08:53:10 +0000402 void DebugBreak();
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000403#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404
405 // ---------------------------------------------------------------------------
406 // Exception handling
407
408 // Push a new try handler and link into try handler chain.
409 // The return address must be passed in register lr.
410 // On exit, r0 contains TOS (code slot).
411 void PushTryHandler(CodeLocation try_location, HandlerType type);
412
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000413 // Unlink the stack handler on top of the stack from the try handler chain.
414 // Must preserve the result register.
415 void PopTryHandler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000417 // Passes thrown value (in r0) to the handler of top of the try handler chain.
418 void Throw(Register value);
419
420 // Propagates an uncatchable exception to the top of the current JS stack's
421 // handler chain.
422 void ThrowUncatchable(UncatchableExceptionType type, Register value);
423
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424 // ---------------------------------------------------------------------------
425 // Inline caching support
426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000427 // Generate code for checking access rights - used for security checks
428 // on access to global objects across environments. The holder register
429 // is left untouched, whereas both scratch registers are clobbered.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000430 void CheckAccessGlobalProxy(Register holder_reg,
431 Register scratch,
432 Label* miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000433
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000434 inline void MarkCode(NopMarkerTypes type) {
435 nop(type);
436 }
437
438 // Check if the given instruction is a 'type' marker.
439 // ie. check if is is a mov r<type>, r<type> (referenced as nop(type))
440 // These instructions are generated to mark special location in the code,
441 // like some special IC code.
442 static inline bool IsMarkedCode(Instr instr, int type) {
443 ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
444 return IsNop(instr, type);
445 }
446
447
448 static inline int GetCodeMarker(Instr instr) {
449 int dst_reg_offset = 12;
450 int dst_mask = 0xf << dst_reg_offset;
451 int src_mask = 0xf;
452 int dst_reg = (instr & dst_mask) >> dst_reg_offset;
453 int src_reg = instr & src_mask;
454 uint32_t non_register_mask = ~(dst_mask | src_mask);
455 uint32_t mov_mask = al | 13 << 21;
456
457 // Return <n> if we have a mov rn rn, else return -1.
458 int type = ((instr & non_register_mask) == mov_mask) &&
459 (dst_reg == src_reg) &&
460 (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER)
461 ? src_reg
462 : -1;
463 ASSERT((type == -1) ||
464 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
465 return type;
466 }
467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468
469 // ---------------------------------------------------------------------------
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000470 // Allocation support
471
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000472 // Allocate an object in new space. The object_size is specified
473 // either in bytes or in words if the allocation flag SIZE_IN_WORDS
474 // is passed. If the new space is exhausted control continues at the
475 // gc_required label. The allocated object is returned in result. If
476 // the flag tag_allocated_object is true the result is tagged as as
477 // a heap object. All registers are clobbered also when control
478 // continues at the gc_required label.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000479 void AllocateInNewSpace(int object_size,
480 Register result,
481 Register scratch1,
482 Register scratch2,
483 Label* gc_required,
484 AllocationFlags flags);
485 void AllocateInNewSpace(Register object_size,
486 Register result,
487 Register scratch1,
488 Register scratch2,
489 Label* gc_required,
490 AllocationFlags flags);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000491
492 // Undo allocation in new space. The object passed and objects allocated after
493 // it will no longer be allocated. The caller must make sure that no pointers
494 // are left to the object(s) no longer allocated as they would be invalid when
495 // allocation is undone.
496 void UndoAllocationInNewSpace(Register object, Register scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000497
ager@chromium.org5c838252010-02-19 08:53:10 +0000498
499 void AllocateTwoByteString(Register result,
500 Register length,
501 Register scratch1,
502 Register scratch2,
503 Register scratch3,
504 Label* gc_required);
505 void AllocateAsciiString(Register result,
506 Register length,
507 Register scratch1,
508 Register scratch2,
509 Register scratch3,
510 Label* gc_required);
511 void AllocateTwoByteConsString(Register result,
512 Register length,
513 Register scratch1,
514 Register scratch2,
515 Label* gc_required);
516 void AllocateAsciiConsString(Register result,
517 Register length,
518 Register scratch1,
519 Register scratch2,
520 Label* gc_required);
521
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000522 // Allocates a heap number or jumps to the gc_required label if the young
523 // space is full and a scavenge is needed. All registers are clobbered also
524 // when control continues at the gc_required label.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000525 void AllocateHeapNumber(Register result,
526 Register scratch1,
527 Register scratch2,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000528 Register heap_number_map,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000529 Label* gc_required);
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000530 void AllocateHeapNumberWithValue(Register result,
531 DwVfpRegister value,
532 Register scratch1,
533 Register scratch2,
534 Register heap_number_map,
535 Label* gc_required);
536
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000537 // Copies a fixed number of fields of heap objects from src to dst.
538 void CopyFields(Register dst, Register src, RegList temps, int field_count);
ager@chromium.org5c838252010-02-19 08:53:10 +0000539
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000540 // Copies a number of bytes from src to dst. All registers are clobbered. On
541 // exit src and dst will point to the place just after where the last byte was
542 // read or written and length will be zero.
543 void CopyBytes(Register src,
544 Register dst,
545 Register length,
546 Register scratch);
547
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000548 // ---------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000549 // Support functions.
550
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000551 // Try to get function prototype of a function and puts the value in
552 // the result register. Checks that the function really is a
553 // function and jumps to the miss label if the fast checks fail. The
554 // function register will be untouched; the other registers may be
555 // clobbered.
556 void TryGetFunctionPrototype(Register function,
557 Register result,
558 Register scratch,
559 Label* miss);
560
561 // Compare object type for heap object. heap_object contains a non-Smi
562 // whose object type should be compared with the given type. This both
563 // sets the flags and leaves the object type in the type_reg register.
564 // It leaves the map in the map register (unless the type_reg and map register
565 // are the same register). It leaves the heap object in the heap_object
566 // register unless the heap_object register is the same register as one of the
ager@chromium.orga1645e22009-09-09 19:27:10 +0000567 // other registers.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000568 void CompareObjectType(Register heap_object,
569 Register map,
570 Register type_reg,
571 InstanceType type);
572
ager@chromium.orga1645e22009-09-09 19:27:10 +0000573 // Compare instance type in a map. map contains a valid map object whose
574 // object type should be compared with the given type. This both
575 // sets the flags and leaves the object type in the type_reg register. It
576 // leaves the heap object in the heap_object register unless the heap_object
577 // register is the same register as type_reg.
578 void CompareInstanceType(Register map,
579 Register type_reg,
580 InstanceType type);
581
ager@chromium.org5c838252010-02-19 08:53:10 +0000582
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000583 // Check if a map for a JSObject indicates that the object has fast elements.
584 // Jump to the specified label if it does not.
585 void CheckFastElements(Register map,
586 Register scratch,
587 Label* fail);
588
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000589 // Check if the map of an object is equal to a specified map (either
590 // given directly or as an index into the root list) and branch to
591 // label if not. Skip the smi check if not required (object is known
592 // to be a heap object)
ager@chromium.org5c838252010-02-19 08:53:10 +0000593 void CheckMap(Register obj,
594 Register scratch,
595 Handle<Map> map,
596 Label* fail,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000597 SmiCheckType smi_check_type);
ager@chromium.org5c838252010-02-19 08:53:10 +0000598
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000599
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000600 void CheckMap(Register obj,
601 Register scratch,
602 Heap::RootListIndex index,
603 Label* fail,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000604 SmiCheckType smi_check_type);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000605
606
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000607 // Check if the map of an object is equal to a specified map and branch to a
608 // specified target if equal. Skip the smi check if not required (object is
609 // known to be a heap object)
610 void DispatchMap(Register obj,
611 Register scratch,
612 Handle<Map> map,
613 Handle<Code> success,
614 SmiCheckType smi_check_type);
615
616
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000617 // Compare the object in a register to a value from the root list.
618 // Uses the ip register as scratch.
619 void CompareRoot(Register obj, Heap::RootListIndex index);
620
621
ager@chromium.org5c838252010-02-19 08:53:10 +0000622 // Load and check the instance type of an object for being a string.
623 // Loads the type into the second argument register.
624 // Returns a condition that will be enabled if the object was a string.
625 Condition IsObjectStringType(Register obj,
626 Register type) {
627 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
628 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
629 tst(type, Operand(kIsNotStringMask));
630 ASSERT_EQ(0, kStringTag);
631 return eq;
632 }
633
634
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000635 // Generates code for reporting that an illegal operation has
636 // occurred.
637 void IllegalOperation(int num_arguments);
638
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000639 // Picks out an array index from the hash field.
640 // Register use:
641 // hash - holds the index's hash. Clobbered.
642 // index - holds the overwritten index on exit.
643 void IndexFromHash(Register hash, Register index);
644
ager@chromium.org5c838252010-02-19 08:53:10 +0000645 // Get the number of least significant bits from a register
646 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000647 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits);
ager@chromium.org5c838252010-02-19 08:53:10 +0000648
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000649 // Uses VFP instructions to Convert a Smi to a double.
650 void IntegerToDoubleConversionWithVFP3(Register inReg,
651 Register outHighReg,
652 Register outLowReg);
653
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000654 // Load the value of a number object into a VFP double register. If the object
655 // is not a number a jump to the label not_number is performed and the VFP
656 // double register is unchanged.
657 void ObjectToDoubleVFPRegister(
658 Register object,
659 DwVfpRegister value,
660 Register scratch1,
661 Register scratch2,
662 Register heap_number_map,
663 SwVfpRegister scratch3,
664 Label* not_number,
665 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS);
666
667 // Load the value of a smi object into a VFP double register. The register
668 // scratch1 can be the same register as smi in which case smi will hold the
669 // untagged value afterwards.
670 void SmiToDoubleVFPRegister(Register smi,
671 DwVfpRegister value,
672 Register scratch1,
673 SwVfpRegister scratch2);
674
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000675 // Convert the HeapNumber pointed to by source to a 32bits signed integer
676 // dest. If the HeapNumber does not fit into a 32bits signed integer branch
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000677 // to not_int32 label. If VFP3 is available double_scratch is used but not
678 // scratch2.
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000679 void ConvertToInt32(Register source,
680 Register dest,
681 Register scratch,
682 Register scratch2,
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000683 DwVfpRegister double_scratch,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000684 Label *not_int32);
685
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000686 // Truncates a double using a specific rounding mode.
687 // Clears the z flag (ne condition) if an overflow occurs.
688 // If exact_conversion is true, the z flag is also cleared if the conversion
689 // was inexact, ie. if the double value could not be converted exactly
690 // to a 32bit integer.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000691 void EmitVFPTruncate(VFPRoundingMode rounding_mode,
692 SwVfpRegister result,
693 DwVfpRegister double_input,
694 Register scratch1,
695 Register scratch2,
696 CheckForInexactConversion check
697 = kDontCheckForInexactConversion);
698
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000699 // Helper for EmitECMATruncate.
700 // This will truncate a floating-point value outside of the singed 32bit
701 // integer range to a 32bit signed integer.
702 // Expects the double value loaded in input_high and input_low.
703 // Exits with the answer in 'result'.
704 // Note that this code does not work for values in the 32bit range!
705 void EmitOutOfInt32RangeTruncate(Register result,
706 Register input_high,
707 Register input_low,
708 Register scratch);
709
710 // Performs a truncating conversion of a floating point number as used by
711 // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
712 // Exits with 'result' holding the answer and all other registers clobbered.
713 void EmitECMATruncate(Register result,
714 DwVfpRegister double_input,
715 SwVfpRegister single_scratch,
716 Register scratch,
717 Register scratch2,
718 Register scratch3);
719
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000720 // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
721 // instruction. On pre-ARM5 hardware this routine gives the wrong answer
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000722 // for 0 (31 instead of 32). Source and scratch can be the same in which case
723 // the source is clobbered. Source and zeros can also be the same in which
724 // case scratch should be a different register.
725 void CountLeadingZeros(Register zeros,
726 Register source,
727 Register scratch);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000728
729 // ---------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 // Runtime calls
731
732 // Call a code stub.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000733 void CallStub(CodeStub* stub, Condition cond = al);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000735 // Call a code stub and return the code object called. Try to generate
736 // the code if necessary. Do not perform a GC but instead return a retry
737 // after GC failure.
738 MUST_USE_RESULT MaybeObject* TryCallStub(CodeStub* stub, Condition cond = al);
739
ager@chromium.org5c838252010-02-19 08:53:10 +0000740 // Call a code stub.
741 void TailCallStub(CodeStub* stub, Condition cond = al);
742
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000743 // Tail call a code stub (jump) and return the code object called. Try to
744 // generate the code if necessary. Do not perform a GC but instead return
745 // a retry after GC failure.
746 MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub,
747 Condition cond = al);
748
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000749 // Call a runtime routine.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000750 void CallRuntime(const Runtime::Function* f, int num_arguments);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000751 void CallRuntimeSaveDoubles(Runtime::FunctionId id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000752
753 // Convenience function: Same as above, but takes the fid instead.
754 void CallRuntime(Runtime::FunctionId fid, int num_arguments);
755
ager@chromium.org5c838252010-02-19 08:53:10 +0000756 // Convenience function: call an external reference.
757 void CallExternalReference(const ExternalReference& ext,
758 int num_arguments);
759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760 // Tail call of a runtime routine (jump).
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000761 // Like JumpToExternalReference, but also takes care of passing the number
mads.s.ager31e71382008-08-13 09:32:07 +0000762 // of parameters.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000763 void TailCallExternalReference(const ExternalReference& ext,
764 int num_arguments,
765 int result_size);
766
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000767 // Tail call of a runtime routine (jump). Try to generate the code if
768 // necessary. Do not perform a GC but instead return a retry after GC
769 // failure.
770 MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
771 const ExternalReference& ext, int num_arguments, int result_size);
772
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000773 // Convenience function: tail call a runtime routine (jump).
774 void TailCallRuntime(Runtime::FunctionId fid,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000775 int num_arguments,
776 int result_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000778 int CalculateStackPassedWords(int num_reg_arguments,
779 int num_double_arguments);
780
ager@chromium.org357bf652010-04-12 11:30:10 +0000781 // Before calling a C-function from generated code, align arguments on stack.
782 // After aligning the frame, non-register arguments must be stored in
783 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000784 // are word sized. If double arguments are used, this function assumes that
785 // all double arguments are stored before core registers; otherwise the
786 // correct alignment of the double values is not guaranteed.
ager@chromium.org357bf652010-04-12 11:30:10 +0000787 // Some compilers/platforms require the stack to be aligned when calling
788 // C++ code.
789 // Needs a scratch register to do some arithmetic. This register will be
790 // trashed.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000791 void PrepareCallCFunction(int num_reg_arguments,
792 int num_double_registers,
793 Register scratch);
794 void PrepareCallCFunction(int num_reg_arguments,
795 Register scratch);
796
797 // There are two ways of passing double arguments on ARM, depending on
798 // whether soft or hard floating point ABI is used. These functions
799 // abstract parameter passing for the three different ways we call
800 // C functions from generated code.
801 void SetCallCDoubleArguments(DoubleRegister dreg);
802 void SetCallCDoubleArguments(DoubleRegister dreg1, DoubleRegister dreg2);
803 void SetCallCDoubleArguments(DoubleRegister dreg, Register reg);
ager@chromium.org357bf652010-04-12 11:30:10 +0000804
805 // Calls a C function and cleans up the space for arguments allocated
806 // by PrepareCallCFunction. The called function is not allowed to trigger a
807 // garbage collection, since that might move the code and invalidate the
808 // return address (unless this is somehow accounted for by the called
809 // function).
810 void CallCFunction(ExternalReference function, int num_arguments);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 void CallCFunction(Register function, Register scratch, int num_arguments);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000812 void CallCFunction(ExternalReference function,
813 int num_reg_arguments,
814 int num_double_arguments);
815 void CallCFunction(Register function, Register scratch,
816 int num_reg_arguments,
817 int num_double_arguments);
ager@chromium.org357bf652010-04-12 11:30:10 +0000818
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000819 void GetCFunctionDoubleResult(const DoubleRegister dst);
820
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000821 // Calls an API function. Allocates HandleScope, extracts returned value
822 // from handle and propagates exceptions. Restores context.
823 // stack_space - space to be unwound on exit (includes the call js
824 // arguments space and the additional space allocated for the fast call).
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000825 MaybeObject* TryCallApiFunctionAndReturn(ExternalReference function,
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000826 int stack_space);
827
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000828 // Jump to a runtime routine.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000829 void JumpToExternalReference(const ExternalReference& builtin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000831 MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);
832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833 // Invoke specified builtin JavaScript function. Adds an entry to
834 // the unresolved list if the name does not resolve.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000835 void InvokeBuiltin(Builtins::JavaScript id,
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000836 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000837 const CallWrapper& call_wrapper = NullCallWrapper());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000838
839 // Store the code object for the given builtin in the target register and
840 // setup the function in r1.
841 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000843 // Store the function for the given builtin in the target register.
844 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000846 Handle<Object> CodeObject() {
847 ASSERT(!code_object_.is_null());
848 return code_object_;
849 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000850
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851
852 // ---------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000853 // StatsCounter support
854
855 void SetCounter(StatsCounter* counter, int value,
856 Register scratch1, Register scratch2);
857 void IncrementCounter(StatsCounter* counter, int value,
858 Register scratch1, Register scratch2);
859 void DecrementCounter(StatsCounter* counter, int value,
860 Register scratch1, Register scratch2);
861
862
863 // ---------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 // Debugging
865
ager@chromium.org378b34e2011-01-28 08:04:38 +0000866 // Calls Abort(msg) if the condition cond is not satisfied.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867 // Use --debug_code to enable.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000868 void Assert(Condition cond, const char* msg);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000869 void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000870 void AssertFastElements(Register elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871
872 // Like Assert(), but always enabled.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000873 void Check(Condition cond, const char* msg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874
875 // Print a message to stdout and abort execution.
876 void Abort(const char* msg);
877
878 // Verify restrictions about code generated in stubs.
879 void set_generating_stub(bool value) { generating_stub_ = value; }
880 bool generating_stub() { return generating_stub_; }
kasper.lund7276f142008-07-30 08:49:36 +0000881 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
882 bool allow_stub_calls() { return allow_stub_calls_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000884 // EABI variant for double arguments in use.
885 bool use_eabi_hardfloat() {
886#if USE_EABI_HARDFLOAT
887 return true;
888#else
889 return false;
890#endif
891 }
892
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000893 // ---------------------------------------------------------------------------
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000894 // Number utilities
895
896 // Check whether the value of reg is a power of two and not zero. If not
897 // control continues at the label not_power_of_two. If reg is a power of two
898 // the register scratch contains the value of (reg - 1) when control falls
899 // through.
900 void JumpIfNotPowerOfTwoOrZero(Register reg,
901 Register scratch,
902 Label* not_power_of_two_or_zero);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 // Check whether the value of reg is a power of two and not zero.
904 // Control falls through if it is, with scratch containing the mask
905 // value (reg - 1).
906 // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is
907 // zero or negative, or jumps to the 'not_power_of_two' label if the value is
908 // strictly positive but not a power of two.
909 void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
910 Register scratch,
911 Label* zero_and_neg,
912 Label* not_power_of_two);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000913
914 // ---------------------------------------------------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000915 // Smi utilities
916
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000917 void SmiTag(Register reg, SBit s = LeaveCC) {
918 add(reg, reg, Operand(reg), s);
919 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000920 void SmiTag(Register dst, Register src, SBit s = LeaveCC) {
921 add(dst, src, Operand(src), s);
922 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000923
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000924 // Try to convert int32 to smi. If the value is to large, preserve
925 // the original value and jump to not_a_smi. Destroys scratch and
926 // sets flags.
927 void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) {
928 mov(scratch, reg);
929 SmiTag(scratch, SetCC);
930 b(vs, not_a_smi);
931 mov(reg, scratch);
932 }
933
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000934 void SmiUntag(Register reg, SBit s = LeaveCC) {
935 mov(reg, Operand(reg, ASR, kSmiTagSize), s);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000936 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000937 void SmiUntag(Register dst, Register src, SBit s = LeaveCC) {
938 mov(dst, Operand(src, ASR, kSmiTagSize), s);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000939 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000940
ager@chromium.org378b34e2011-01-28 08:04:38 +0000941 // Jump the register contains a smi.
942 inline void JumpIfSmi(Register value, Label* smi_label) {
943 tst(value, Operand(kSmiTagMask));
944 b(eq, smi_label);
945 }
946 // Jump if either of the registers contain a non-smi.
947 inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
948 tst(value, Operand(kSmiTagMask));
949 b(ne, not_smi_label);
950 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000951 // Jump if either of the registers contain a non-smi.
952 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
953 // Jump if either of the registers contain a smi.
954 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
955
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000956 // Abort execution if argument is a smi. Used in debug code.
957 void AbortIfSmi(Register object);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000958 void AbortIfNotSmi(Register object);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000959
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000960 // Abort execution if argument is a string. Used in debug code.
961 void AbortIfNotString(Register object);
962
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000963 // Abort execution if argument is not the root value with the given index.
964 void AbortIfNotRootValue(Register src,
965 Heap::RootListIndex root_value_index,
966 const char* message);
967
ager@chromium.org5c838252010-02-19 08:53:10 +0000968 // ---------------------------------------------------------------------------
ager@chromium.org378b34e2011-01-28 08:04:38 +0000969 // HeapNumber utilities
970
971 void JumpIfNotHeapNumber(Register object,
972 Register heap_number_map,
973 Register scratch,
974 Label* on_not_heap_number);
975
976 // ---------------------------------------------------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000977 // String utilities
978
979 // Checks if both objects are sequential ASCII strings and jumps to label
980 // if either is not. Assumes that neither object is a smi.
981 void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
982 Register object2,
983 Register scratch1,
984 Register scratch2,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000985 Label* failure);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000986
987 // Checks if both objects are sequential ASCII strings and jumps to label
988 // if either is not.
989 void JumpIfNotBothSequentialAsciiStrings(Register first,
990 Register second,
991 Register scratch1,
992 Register scratch2,
993 Label* not_flat_ascii_strings);
994
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000995 // Checks if both instance types are sequential ASCII strings and jumps to
996 // label if either is not.
997 void JumpIfBothInstanceTypesAreNotSequentialAscii(
998 Register first_object_instance_type,
999 Register second_object_instance_type,
1000 Register scratch1,
1001 Register scratch2,
1002 Label* failure);
1003
1004 // Check if instance type is sequential ASCII string and jump to label if
1005 // it is not.
1006 void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
1007 Register scratch,
1008 Label* failure);
1009
1010
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001011 // ---------------------------------------------------------------------------
1012 // Patching helpers.
1013
1014 // Get the location of a relocated constant (its address in the constant pool)
1015 // from its load site.
1016 void GetRelocatedValueLocation(Register ldr_location,
1017 Register result);
1018
1019
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001020 void ClampUint8(Register output_reg, Register input_reg);
1021
1022 void ClampDoubleToUint8(Register result_reg,
1023 DoubleRegister input_reg,
1024 DoubleRegister temp_double_reg);
1025
1026
danno@chromium.org40cb8782011-05-25 07:58:50 +00001027 void LoadInstanceDescriptors(Register map, Register descriptors);
1028
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 void CallCFunctionHelper(Register function,
1031 ExternalReference function_reference,
1032 Register scratch,
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001033 int num_reg_arguments,
1034 int num_double_arguments);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035
ager@chromium.org5c838252010-02-19 08:53:10 +00001036 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001037 int CallSize(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001038 void Call(intptr_t target,
1039 RelocInfo::Mode rmode,
1040 Condition cond = al);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001041
1042 // Helper functions for generating invokes.
1043 void InvokePrologue(const ParameterCount& expected,
1044 const ParameterCount& actual,
1045 Handle<Code> code_constant,
1046 Register code_reg,
1047 Label* done,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001048 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001049 const CallWrapper& call_wrapper,
1050 CallKind call_kind);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001051
ager@chromium.org7c537e22008-10-16 08:43:32 +00001052 // Activation support.
1053 void EnterFrame(StackFrame::Type type);
1054 void LeaveFrame(StackFrame::Type type);
ager@chromium.org5c838252010-02-19 08:53:10 +00001055
ager@chromium.orgac091b72010-05-05 07:34:42 +00001056 void InitializeNewString(Register string,
1057 Register length,
1058 Heap::RootListIndex map_index,
1059 Register scratch1,
1060 Register scratch2);
1061
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001062 // Compute memory operands for safepoint stack slots.
1063 static int SafepointRegisterStackIndex(int reg_code);
1064 MemOperand SafepointRegisterSlot(Register reg);
1065 MemOperand SafepointRegistersAndDoublesSlot(Register reg);
1066
ager@chromium.org5c838252010-02-19 08:53:10 +00001067 bool generating_stub_;
1068 bool allow_stub_calls_;
1069 // This handle will be patched with the code object on installation.
1070 Handle<Object> code_object_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001071
1072 // Needs access to SafepointRegisterStackIndex for optimized frame
1073 // traversal.
1074 friend class OptimizedFrame;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075};
1076
1077
ager@chromium.org4af710e2009-09-15 12:20:11 +00001078#ifdef ENABLE_DEBUGGER_SUPPORT
1079// The code patcher is used to patch (typically) small parts of code e.g. for
1080// debugging and other types of instrumentation. When using the code patcher
1081// the exact number of bytes specified must be emitted. It is not legal to emit
1082// relocation information. If any of these constraints are violated it causes
1083// an assertion to fail.
1084class CodePatcher {
1085 public:
1086 CodePatcher(byte* address, int instructions);
1087 virtual ~CodePatcher();
1088
1089 // Macro assembler to emit code.
1090 MacroAssembler* masm() { return &masm_; }
1091
1092 // Emit an instruction directly.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001093 void Emit(Instr instr);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001094
1095 // Emit an address directly.
1096 void Emit(Address addr);
1097
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001098 // Emit the condition part of an instruction leaving the rest of the current
1099 // instruction unchanged.
1100 void EmitCondition(Condition cond);
1101
ager@chromium.org4af710e2009-09-15 12:20:11 +00001102 private:
1103 byte* address_; // The address of the code being patched.
1104 int instructions_; // Number of instructions of the expected patch size.
1105 int size_; // Number of bytes of the expected patch size.
1106 MacroAssembler masm_; // Macro assembler used to generate the code.
1107};
1108#endif // ENABLE_DEBUGGER_SUPPORT
1109
1110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111// -----------------------------------------------------------------------------
1112// Static helper functions.
1113
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001114static MemOperand ContextOperand(Register context, int index) {
1115 return MemOperand(context, Context::SlotOffset(index));
1116}
1117
1118
1119static inline MemOperand GlobalObjectOperand() {
1120 return ContextOperand(cp, Context::GLOBAL_INDEX);
1121}
1122
1123
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001124#ifdef GENERATED_CODE_COVERAGE
1125#define CODE_COVERAGE_STRINGIFY(x) #x
1126#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1127#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1128#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
1129#else
1130#define ACCESS_MASM(masm) masm->
1131#endif
1132
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133
1134} } // namespace v8::internal
1135
ager@chromium.org5ec48922009-05-05 07:25:34 +00001136#endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_