blob: 8fa197c07c10133798b033117150ba38482e176b [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
5#ifndef V8_ARM_MACRO_ASSEMBLER_ARM_H_
6#define V8_ARM_MACRO_ASSEMBLER_ARM_H_
7
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/assembler.h"
9#include "src/bailout-reason.h"
10#include "src/frames.h"
11#include "src/globals.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000012
13namespace v8 {
14namespace internal {
15
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016// Give alias names to registers for calling conventions.
17const Register kReturnRegister0 = {Register::kCode_r0};
18const Register kReturnRegister1 = {Register::kCode_r1};
Ben Murdoch097c5b22016-05-18 11:27:45 +010019const Register kReturnRegister2 = {Register::kCode_r2};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020const Register kJSFunctionRegister = {Register::kCode_r1};
21const Register kContextRegister = {Register::kCode_r7};
Ben Murdochc5610432016-08-08 18:44:38 +010022const Register kAllocateSizeRegister = {Register::kCode_r1};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023const Register kInterpreterAccumulatorRegister = {Register::kCode_r0};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_r5};
25const Register kInterpreterBytecodeArrayRegister = {Register::kCode_r6};
26const Register kInterpreterDispatchTableRegister = {Register::kCode_r8};
27const Register kJavaScriptCallArgCountRegister = {Register::kCode_r0};
28const Register kJavaScriptCallNewTargetRegister = {Register::kCode_r3};
29const Register kRuntimeCallFunctionRegister = {Register::kCode_r1};
30const Register kRuntimeCallArgCountRegister = {Register::kCode_r0};
31
Andrei Popescu31002712010-02-23 13:46:05 +000032// ----------------------------------------------------------------------------
33// Static helper functions
34
35// Generate a MemOperand for loading a field from an object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010036inline MemOperand FieldMemOperand(Register object, int offset) {
Andrei Popescu31002712010-02-23 13:46:05 +000037 return MemOperand(object, offset - kHeapObjectTag);
38}
39
Steve Blocka7e24c12009-10-30 11:49:00 +000040
41// Give alias names to registers
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042const Register cp = {Register::kCode_r7}; // JavaScript context pointer.
43const Register pp = {Register::kCode_r8}; // Constant pool pointer.
44const Register kRootRegister = {Register::kCode_r10}; // Roots array pointer.
Steve Blocka7e24c12009-10-30 11:49:00 +000045
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046// Flags used for AllocateHeapNumber
47enum TaggingMode {
48 // Tag the result.
49 TAG_RESULT,
50 // Don't tag
51 DONT_TAG_RESULT
Steve Block8defd9f2010-07-08 12:39:36 +010052};
53
54
Ben Murdoch3ef787d2012-04-12 10:51:47 +010055enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
56enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057enum PointersToHereCheck {
58 kPointersToHereMaybeInteresting,
59 kPointersToHereAreAlwaysInteresting
60};
Ben Murdoch3ef787d2012-04-12 10:51:47 +010061enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
62
63
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064Register GetRegisterThatIsNotOneOf(Register reg1,
65 Register reg2 = no_reg,
66 Register reg3 = no_reg,
67 Register reg4 = no_reg,
68 Register reg5 = no_reg,
69 Register reg6 = no_reg);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010070
71
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072#ifdef DEBUG
73bool AreAliased(Register reg1,
74 Register reg2,
75 Register reg3 = no_reg,
76 Register reg4 = no_reg,
77 Register reg5 = no_reg,
78 Register reg6 = no_reg,
79 Register reg7 = no_reg,
80 Register reg8 = no_reg);
81#endif
82
83
84enum TargetAddressStorageMode {
85 CAN_INLINE_TARGET_ADDRESS,
86 NEVER_INLINE_TARGET_ADDRESS
87};
88
Steve Blocka7e24c12009-10-30 11:49:00 +000089// MacroAssembler implements a collection of frequently used macros.
90class MacroAssembler: public Assembler {
91 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 MacroAssembler(Isolate* isolate, void* buffer, int size,
93 CodeObjectRequired create_code_object);
Steve Blocka7e24c12009-10-30 11:49:00 +000094
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095
96 // Returns the size of a call in instructions. Note, the value returned is
97 // only valid as long as no entries are added to the constant pool between
98 // checking the call size and emitting the actual call.
99 static int CallSize(Register target, Condition cond = al);
100 int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al);
101 int CallStubSize(CodeStub* stub,
102 TypeFeedbackId ast_id = TypeFeedbackId::None(),
103 Condition cond = al);
104 static int CallSizeNotPredictableCodeSize(Isolate* isolate,
105 Address target,
106 RelocInfo::Mode rmode,
107 Condition cond = al);
108
Andrei Popescu31002712010-02-23 13:46:05 +0000109 // Jump, Call, and Ret pseudo instructions implementing inter-working.
Steve Blocka7e24c12009-10-30 11:49:00 +0000110 void Jump(Register target, Condition cond = al);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000111 void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
113 void Call(Register target, Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 void Call(Address target, RelocInfo::Mode rmode,
115 Condition cond = al,
116 TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS);
117 int CallSize(Handle<Code> code,
118 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
119 TypeFeedbackId ast_id = TypeFeedbackId::None(),
120 Condition cond = al);
Ben Murdoch257744e2011-11-30 15:57:28 +0000121 void Call(Handle<Code> code,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000122 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 TypeFeedbackId ast_id = TypeFeedbackId::None(),
124 Condition cond = al,
125 TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 void Ret(Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000127
128 // Emit code to discard a non-negative number of pointer-sized elements
129 // from the stack, clobbering only the sp register.
130 void Drop(int count, Condition cond = al);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100131 void Drop(Register count, Condition cond = al);
Leon Clarkee46be812010-01-19 14:06:41 +0000132
Ben Murdochb0fe1622011-05-05 13:52:32 +0100133 void Ret(int drop, Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100134
135 // Swap two registers. If the scratch register is omitted then a slightly
136 // less efficient form using xor instead of mov is emitted.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100137 void Swap(Register reg1,
138 Register reg2,
139 Register scratch = no_reg,
140 Condition cond = al);
Steve Block6ded16b2010-05-10 14:33:55 +0100141
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 void Mls(Register dst, Register src1, Register src2, Register srcA,
143 Condition cond = al);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100144 void And(Register dst, Register src1, const Operand& src2,
145 Condition cond = al);
146 void Ubfx(Register dst, Register src, int lsb, int width,
147 Condition cond = al);
148 void Sbfx(Register dst, Register src, int lsb, int width,
149 Condition cond = al);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100150 // The scratch register is not used for ARMv7.
151 // scratch can be the same register as src (in which case it is trashed), but
152 // not the same as dst.
153 void Bfi(Register dst,
154 Register src,
155 Register scratch,
156 int lsb,
157 int width,
158 Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 void Bfc(Register dst, Register src, int lsb, int width, Condition cond = al);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100160
Leon Clarkee46be812010-01-19 14:06:41 +0000161 void Call(Label* target);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000162 void Push(Register src) { push(src); }
163 void Pop(Register dst) { pop(dst); }
Ben Murdoch257744e2011-11-30 15:57:28 +0000164
165 // Register move. May do nothing if the registers are identical.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 void Move(Register dst, Smi* smi) { mov(dst, Operand(smi)); }
Leon Clarkee46be812010-01-19 14:06:41 +0000167 void Move(Register dst, Handle<Object> value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000168 void Move(Register dst, Register src, Condition cond = al);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000169 void Move(Register dst, const Operand& src, SBit sbit = LeaveCC,
170 Condition cond = al) {
171 if (!src.is_reg() || !src.rm().is(dst) || sbit != LeaveCC) {
172 mov(dst, src, sbit, cond);
173 }
174 }
175 void Move(DwVfpRegister dst, DwVfpRegister src);
176
177 void Load(Register dst, const MemOperand& src, Representation r);
178 void Store(Register src, const MemOperand& dst, Representation r);
Ben Murdoch257744e2011-11-30 15:57:28 +0000179
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 // Load an object from the root table.
181 void LoadRoot(Register destination,
182 Heap::RootListIndex index,
183 Condition cond = al);
Kristian Monsen25f61362010-05-21 11:50:48 +0100184 // Store an object to the root table.
185 void StoreRoot(Register source,
186 Heap::RootListIndex index,
187 Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +0000188
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100189 // ---------------------------------------------------------------------------
190 // GC Support
Steve Block6ded16b2010-05-10 14:33:55 +0100191
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100192 void IncrementalMarkingRecordWriteHelper(Register object,
193 Register value,
194 Register address);
Steve Block6ded16b2010-05-10 14:33:55 +0100195
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100196 enum RememberedSetFinalAction {
197 kReturnAtEnd,
198 kFallThroughAtEnd
199 };
200
201 // Record in the remembered set the fact that we have a pointer to new space
202 // at the address pointed to by the addr register. Only works if addr is not
203 // in new space.
204 void RememberedSetHelper(Register object, // Used for debug code.
205 Register addr,
206 Register scratch,
207 SaveFPRegsMode save_fp,
208 RememberedSetFinalAction and_then);
209
210 void CheckPageFlag(Register object,
211 Register scratch,
212 int mask,
213 Condition cc,
214 Label* condition_met);
215
216 // Check if object is in new space. Jumps if the object is not in new space.
217 // The register scratch can be object itself, but scratch will be clobbered.
218 void JumpIfNotInNewSpace(Register object,
219 Register scratch,
220 Label* branch) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100221 InNewSpace(object, scratch, eq, branch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100222 }
223
224 // Check if object is in new space. Jumps if the object is in new space.
225 // The register scratch can be object itself, but it will be clobbered.
226 void JumpIfInNewSpace(Register object,
227 Register scratch,
228 Label* branch) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100229 InNewSpace(object, scratch, ne, branch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 }
231
232 // Check if an object has a given incremental marking color.
233 void HasColor(Register object,
234 Register scratch0,
235 Register scratch1,
236 Label* has_color,
237 int first_bit,
238 int second_bit);
239
240 void JumpIfBlack(Register object,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100241 Register scratch0,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100242 Register scratch1,
243 Label* on_black);
Steve Blocka7e24c12009-10-30 11:49:00 +0000244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 // Checks the color of an object. If the object is white we jump to the
246 // incremental marker.
247 void JumpIfWhite(Register value, Register scratch1, Register scratch2,
248 Register scratch3, Label* value_is_white);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100249
250 // Notify the garbage collector that we wrote a pointer into an object.
251 // |object| is the object being stored into, |value| is the object being
252 // stored. value and scratch registers are clobbered by the operation.
253 // The offset is the offset from the start of the object, not the offset from
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 // the tagged HeapObject pointer. For use with FieldMemOperand(reg, off).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100255 void RecordWriteField(
256 Register object,
257 int offset,
258 Register value,
259 Register scratch,
260 LinkRegisterStatus lr_status,
261 SaveFPRegsMode save_fp,
262 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 SmiCheck smi_check = INLINE_SMI_CHECK,
264 PointersToHereCheck pointers_to_here_check_for_value =
265 kPointersToHereMaybeInteresting);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100266
267 // As above, but the offset has the tag presubtracted. For use with
268 // MemOperand(reg, off).
269 inline void RecordWriteContextSlot(
270 Register context,
271 int offset,
272 Register value,
273 Register scratch,
274 LinkRegisterStatus lr_status,
275 SaveFPRegsMode save_fp,
276 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277 SmiCheck smi_check = INLINE_SMI_CHECK,
278 PointersToHereCheck pointers_to_here_check_for_value =
279 kPointersToHereMaybeInteresting) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100280 RecordWriteField(context,
281 offset + kHeapObjectTag,
282 value,
283 scratch,
284 lr_status,
285 save_fp,
286 remembered_set_action,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 smi_check,
288 pointers_to_here_check_for_value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100289 }
290
Ben Murdoch097c5b22016-05-18 11:27:45 +0100291 // Notify the garbage collector that we wrote a code entry into a
292 // JSFunction. Only scratch is clobbered by the operation.
293 void RecordWriteCodeEntryField(Register js_function, Register code_entry,
294 Register scratch);
295
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296 void RecordWriteForMap(
297 Register object,
298 Register map,
299 Register dst,
300 LinkRegisterStatus lr_status,
301 SaveFPRegsMode save_fp);
302
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100303 // For a given |object| notify the garbage collector that the slot |address|
304 // has been written. |value| is the object being stored. The value and
305 // address registers are clobbered by the operation.
306 void RecordWrite(
307 Register object,
308 Register address,
309 Register value,
310 LinkRegisterStatus lr_status,
311 SaveFPRegsMode save_fp,
312 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000313 SmiCheck smi_check = INLINE_SMI_CHECK,
314 PointersToHereCheck pointers_to_here_check_for_value =
315 kPointersToHereMaybeInteresting);
Steve Block8defd9f2010-07-08 12:39:36 +0100316
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000317 // Push a handle.
318 void Push(Handle<Object> handle);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000320
Steve Block6ded16b2010-05-10 14:33:55 +0100321 // Push two registers. Pushes leftmost register first (to highest address).
322 void Push(Register src1, Register src2, Condition cond = al) {
Steve Block6ded16b2010-05-10 14:33:55 +0100323 if (src1.code() > src2.code()) {
324 stm(db_w, sp, src1.bit() | src2.bit(), cond);
325 } else {
326 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
327 str(src2, MemOperand(sp, 4, NegPreIndex), cond);
328 }
329 }
330
331 // Push three registers. Pushes leftmost register first (to highest address).
332 void Push(Register src1, Register src2, Register src3, Condition cond = al) {
Steve Block6ded16b2010-05-10 14:33:55 +0100333 if (src1.code() > src2.code()) {
334 if (src2.code() > src3.code()) {
335 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
336 } else {
337 stm(db_w, sp, src1.bit() | src2.bit(), cond);
338 str(src3, MemOperand(sp, 4, NegPreIndex), cond);
339 }
340 } else {
341 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
342 Push(src2, src3, cond);
343 }
344 }
345
346 // Push four registers. Pushes leftmost register first (to highest address).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100347 void Push(Register src1,
348 Register src2,
349 Register src3,
350 Register src4,
351 Condition cond = al) {
Steve Block6ded16b2010-05-10 14:33:55 +0100352 if (src1.code() > src2.code()) {
353 if (src2.code() > src3.code()) {
354 if (src3.code() > src4.code()) {
355 stm(db_w,
356 sp,
357 src1.bit() | src2.bit() | src3.bit() | src4.bit(),
358 cond);
359 } else {
360 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
361 str(src4, MemOperand(sp, 4, NegPreIndex), cond);
362 }
363 } else {
364 stm(db_w, sp, src1.bit() | src2.bit(), cond);
365 Push(src3, src4, cond);
366 }
367 } else {
368 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
369 Push(src2, src3, src4, cond);
370 }
371 }
372
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 // Push five registers. Pushes leftmost register first (to highest address).
374 void Push(Register src1, Register src2, Register src3, Register src4,
375 Register src5, Condition cond = al) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376 if (src1.code() > src2.code()) {
377 if (src2.code() > src3.code()) {
378 if (src3.code() > src4.code()) {
379 if (src4.code() > src5.code()) {
380 stm(db_w, sp,
381 src1.bit() | src2.bit() | src3.bit() | src4.bit() | src5.bit(),
382 cond);
383 } else {
384 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit() | src4.bit(),
385 cond);
386 str(src5, MemOperand(sp, 4, NegPreIndex), cond);
387 }
388 } else {
389 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
390 Push(src4, src5, cond);
391 }
392 } else {
393 stm(db_w, sp, src1.bit() | src2.bit(), cond);
394 Push(src3, src4, src5, cond);
395 }
396 } else {
397 str(src1, MemOperand(sp, 4, NegPreIndex), cond);
398 Push(src2, src3, src4, src5, cond);
399 }
400 }
401
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100402 // Pop two registers. Pops rightmost register first (from lower address).
403 void Pop(Register src1, Register src2, Condition cond = al) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 DCHECK(!src1.is(src2));
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100405 if (src1.code() > src2.code()) {
406 ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
407 } else {
408 ldr(src2, MemOperand(sp, 4, PostIndex), cond);
409 ldr(src1, MemOperand(sp, 4, PostIndex), cond);
410 }
411 }
412
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100413 // Pop three registers. Pops rightmost register first (from lower address).
414 void Pop(Register src1, Register src2, Register src3, Condition cond = al) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 DCHECK(!AreAliased(src1, src2, src3));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100416 if (src1.code() > src2.code()) {
417 if (src2.code() > src3.code()) {
418 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
419 } else {
420 ldr(src3, MemOperand(sp, 4, PostIndex), cond);
421 ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
422 }
423 } else {
424 Pop(src2, src3, cond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425 ldr(src1, MemOperand(sp, 4, PostIndex), cond);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100426 }
427 }
428
429 // Pop four registers. Pops rightmost register first (from lower address).
430 void Pop(Register src1,
431 Register src2,
432 Register src3,
433 Register src4,
434 Condition cond = al) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435 DCHECK(!AreAliased(src1, src2, src3, src4));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100436 if (src1.code() > src2.code()) {
437 if (src2.code() > src3.code()) {
438 if (src3.code() > src4.code()) {
439 ldm(ia_w,
440 sp,
441 src1.bit() | src2.bit() | src3.bit() | src4.bit(),
442 cond);
443 } else {
444 ldr(src4, MemOperand(sp, 4, PostIndex), cond);
445 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
446 }
447 } else {
448 Pop(src3, src4, cond);
449 ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
450 }
451 } else {
452 Pop(src2, src3, src4, cond);
453 ldr(src1, MemOperand(sp, 4, PostIndex), cond);
454 }
455 }
456
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457 // Push a fixed frame, consisting of lr, fp, constant pool (if
Ben Murdochda12d292016-06-02 14:46:10 +0100458 // FLAG_enable_embedded_constant_pool)
459 void PushCommonFrame(Register marker_reg = no_reg);
460
461 // Push a standard frame, consisting of lr, fp, constant pool (if
462 // FLAG_enable_embedded_constant_pool), context and JS function
463 void PushStandardFrame(Register function_reg);
464
465 void PopCommonFrame(Register marker_reg = no_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466
Ben Murdochb0fe1622011-05-05 13:52:32 +0100467 // Push and pop the registers that can hold pointers, as defined by the
468 // RegList constant kSafepointSavedRegisters.
469 void PushSafepointRegisters();
470 void PopSafepointRegisters();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100471 // Store value in register src in the safepoint stack slot for
472 // register dst.
473 void StoreToSafepointRegisterSlot(Register src, Register dst);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100474 // Load the value of the src register from its safepoint stack slot
475 // into register dst.
476 void LoadFromSafepointRegisterSlot(Register dst, Register src);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100477
Leon Clarkef7060e22010-06-03 12:02:55 +0100478 // Load two consecutive registers with two consecutive memory locations.
479 void Ldrd(Register dst1,
480 Register dst2,
481 const MemOperand& src,
482 Condition cond = al);
483
484 // Store two consecutive registers to two consecutive memory locations.
485 void Strd(Register src1,
486 Register src2,
487 const MemOperand& dst,
488 Condition cond = al);
489
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490 // If the value is a NaN, canonicalize the value else, do nothing.
491 void VFPCanonicalizeNaN(const DwVfpRegister dst,
492 const DwVfpRegister src,
493 const Condition cond = al);
494 void VFPCanonicalizeNaN(const DwVfpRegister value,
495 const Condition cond = al) {
496 VFPCanonicalizeNaN(value, value, cond);
497 }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100498
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 // Compare single values and move the result to the normal condition flags.
500 void VFPCompareAndSetFlags(const SwVfpRegister src1, const SwVfpRegister src2,
501 const Condition cond = al);
502 void VFPCompareAndSetFlags(const SwVfpRegister src1, const float src2,
503 const Condition cond = al);
504
Ben Murdochb8e0da22011-05-16 14:20:40 +0100505 // Compare double values and move the result to the normal condition flags.
506 void VFPCompareAndSetFlags(const DwVfpRegister src1,
507 const DwVfpRegister src2,
508 const Condition cond = al);
509 void VFPCompareAndSetFlags(const DwVfpRegister src1,
510 const double src2,
511 const Condition cond = al);
512
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 // Compare single values and then load the fpscr flags to a register.
514 void VFPCompareAndLoadFlags(const SwVfpRegister src1,
515 const SwVfpRegister src2,
516 const Register fpscr_flags,
517 const Condition cond = al);
518 void VFPCompareAndLoadFlags(const SwVfpRegister src1, const float src2,
519 const Register fpscr_flags,
520 const Condition cond = al);
521
Ben Murdochb8e0da22011-05-16 14:20:40 +0100522 // Compare double values and then load the fpscr flags to a register.
523 void VFPCompareAndLoadFlags(const DwVfpRegister src1,
524 const DwVfpRegister src2,
525 const Register fpscr_flags,
526 const Condition cond = al);
527 void VFPCompareAndLoadFlags(const DwVfpRegister src1,
528 const double src2,
529 const Register fpscr_flags,
530 const Condition cond = al);
531
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000532 void Vmov(const DwVfpRegister dst,
533 const double imm,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 const Register scratch = no_reg);
535
536 void VmovHigh(Register dst, DwVfpRegister src);
537 void VmovHigh(DwVfpRegister dst, Register src);
538 void VmovLow(Register dst, DwVfpRegister src);
539 void VmovLow(DwVfpRegister dst, Register src);
540
Ben Murdochda12d292016-06-02 14:46:10 +0100541 void LslPair(Register dst_low, Register dst_high, Register src_low,
542 Register src_high, Register scratch, Register shift);
543 void LslPair(Register dst_low, Register dst_high, Register src_low,
544 Register src_high, uint32_t shift);
545 void LsrPair(Register dst_low, Register dst_high, Register src_low,
546 Register src_high, Register scratch, Register shift);
547 void LsrPair(Register dst_low, Register dst_high, Register src_low,
548 Register src_high, uint32_t shift);
549 void AsrPair(Register dst_low, Register dst_high, Register src_low,
550 Register src_high, Register scratch, Register shift);
551 void AsrPair(Register dst_low, Register dst_high, Register src_low,
552 Register src_high, uint32_t shift);
553
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 // Loads the number from object into dst register.
555 // If |object| is neither smi nor heap number, |not_number| is jumped to
556 // with |object| still intact.
557 void LoadNumber(Register object,
558 LowDwVfpRegister dst,
559 Register heap_number_map,
560 Register scratch,
561 Label* not_number);
562
563 // Loads the number from object into double_dst in the double format.
564 // Control will jump to not_int32 if the value cannot be exactly represented
565 // by a 32-bit integer.
566 // Floating point value in the 32-bit integer range that are not exact integer
567 // won't be loaded.
568 void LoadNumberAsInt32Double(Register object,
569 DwVfpRegister double_dst,
570 Register heap_number_map,
571 Register scratch,
572 LowDwVfpRegister double_scratch,
573 Label* not_int32);
574
575 // Loads the number from object into dst as a 32-bit integer.
576 // Control will jump to not_int32 if the object cannot be exactly represented
577 // by a 32-bit integer.
578 // Floating point value in the 32-bit integer range that are not exact integer
579 // won't be converted.
580 void LoadNumberAsInt32(Register object,
581 Register dst,
582 Register heap_number_map,
583 Register scratch,
584 DwVfpRegister double_scratch0,
585 LowDwVfpRegister double_scratch1,
586 Label* not_int32);
587
588 // Generates function and stub prologue code.
Ben Murdochda12d292016-06-02 14:46:10 +0100589 void StubPrologue(StackFrame::Type type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000590 void Prologue(bool code_pre_aging);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000591
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100592 // Enter exit frame.
Steve Block1e0659c2011-05-24 12:43:12 +0100593 // stack_space - extra stack space, used for alignment before call to C.
594 void EnterExitFrame(bool save_doubles, int stack_space = 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000595
596 // Leave the current exit frame. Expects the return value in r0.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100597 // Expect the number of values, pushed prior to the exit frame, to
598 // remove in a register (or no_reg, if there is nothing to remove).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000599 void LeaveExitFrame(bool save_doubles, Register argument_count,
600 bool restore_context,
601 bool argument_count_is_length = false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000602
Steve Block6ded16b2010-05-10 14:33:55 +0100603 // Get the actual activation frame alignment for target environment.
604 static int ActivationFrameAlignment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000605
Steve Blockd0582a62009-12-15 09:54:21 +0000606 void LoadContext(Register dst, int context_chain_length);
607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 // Load the global object from the current context.
609 void LoadGlobalObject(Register dst) {
610 LoadNativeContextSlot(Context::EXTENSION_INDEX, dst);
611 }
612
613 // Load the global proxy from the current context.
614 void LoadGlobalProxy(Register dst) {
615 LoadNativeContextSlot(Context::GLOBAL_PROXY_INDEX, dst);
616 }
617
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100618 // Conditionally load the cached Array transitioned map of type
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 // transitioned_kind from the native context if the map in register
620 // map_in_out is the cached Array map in the native context of
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100621 // expected_kind.
622 void LoadTransitionedArrayMapConditional(
623 ElementsKind expected_kind,
624 ElementsKind transitioned_kind,
625 Register map_in_out,
626 Register scratch,
627 Label* no_map_match);
628
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 void LoadNativeContextSlot(int index, Register dst);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800630
631 // Load the initial map from the global function. The registers
632 // function and map can be the same, function is then overwritten.
633 void LoadGlobalFunctionInitialMap(Register function,
634 Register map,
635 Register scratch);
636
Ben Murdochc7cc0282012-03-05 14:35:55 +0000637 void InitializeRootRegister() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100638 ExternalReference roots_array_start =
639 ExternalReference::roots_array_start(isolate());
640 mov(kRootRegister, Operand(roots_array_start));
Ben Murdochc7cc0282012-03-05 14:35:55 +0000641 }
642
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 // ---------------------------------------------------------------------------
644 // JavaScript invokes
645
Ben Murdochda12d292016-06-02 14:46:10 +0100646 // Removes current frame and its arguments from the stack preserving
647 // the arguments and a return address pushed to the stack for the next call.
648 // Both |callee_args_count| and |caller_args_count_reg| do not include
649 // receiver. |callee_args_count| is not modified, |caller_args_count_reg|
650 // is trashed.
651 void PrepareForTailCall(const ParameterCount& callee_args_count,
652 Register caller_args_count_reg, Register scratch0,
653 Register scratch1);
654
Steve Blocka7e24c12009-10-30 11:49:00 +0000655 // Invoke the JavaScript function code by either calling or jumping.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000656 void InvokeFunctionCode(Register function, Register new_target,
657 const ParameterCount& expected,
658 const ParameterCount& actual, InvokeFlag flag,
659 const CallWrapper& call_wrapper);
660
661 void FloodFunctionIfStepping(Register fun, Register new_target,
662 const ParameterCount& expected,
663 const ParameterCount& actual);
Steve Blocka7e24c12009-10-30 11:49:00 +0000664
665 // Invoke the JavaScript function in the given register. Changes the
666 // current context to the context in the function before invoking.
667 void InvokeFunction(Register function,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000668 Register new_target,
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 const ParameterCount& actual,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100670 InvokeFlag flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000671 const CallWrapper& call_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +0000672
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 void InvokeFunction(Register function,
674 const ParameterCount& expected,
Andrei Popescu402d9372010-02-26 13:31:12 +0000675 const ParameterCount& actual,
Ben Murdoch257744e2011-11-30 15:57:28 +0000676 InvokeFlag flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 const CallWrapper& call_wrapper);
678
679 void InvokeFunction(Handle<JSFunction> function,
680 const ParameterCount& expected,
681 const ParameterCount& actual,
682 InvokeFlag flag,
683 const CallWrapper& call_wrapper);
Andrei Popescu402d9372010-02-26 13:31:12 +0000684
Ben Murdochb0fe1622011-05-05 13:52:32 +0100685 void IsObjectJSStringType(Register object,
686 Register scratch,
687 Label* fail);
Steve Blocka7e24c12009-10-30 11:49:00 +0000688
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000689 void IsObjectNameType(Register object,
690 Register scratch,
691 Label* fail);
692
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 // ---------------------------------------------------------------------------
694 // Debugger Support
695
Andrei Popescu402d9372010-02-26 13:31:12 +0000696 void DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +0000697
698 // ---------------------------------------------------------------------------
699 // Exception handling
700
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000701 // Push a new stack handler and link into stack handler chain.
702 void PushStackHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000703
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000704 // Unlink the stack handler on top of the stack from the stack handler chain.
Leon Clarkee46be812010-01-19 14:06:41 +0000705 // Must preserve the result register.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000706 void PopStackHandler();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100707
Steve Blocka7e24c12009-10-30 11:49:00 +0000708 // ---------------------------------------------------------------------------
709 // Inline caching support
710
Steve Blocka7e24c12009-10-30 11:49:00 +0000711 // Generate code for checking access rights - used for security checks
712 // on access to global objects across environments. The holder register
713 // is left untouched, whereas both scratch registers are clobbered.
714 void CheckAccessGlobalProxy(Register holder_reg,
715 Register scratch,
716 Label* miss);
717
Ben Murdochc7cc0282012-03-05 14:35:55 +0000718 void GetNumberHash(Register t0, Register scratch);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000719
720 void LoadFromNumberDictionary(Label* miss,
721 Register elements,
722 Register key,
723 Register result,
724 Register t0,
725 Register t1,
726 Register t2);
727
728
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800729 inline void MarkCode(NopMarkerTypes type) {
730 nop(type);
731 }
732
733 // Check if the given instruction is a 'type' marker.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100734 // i.e. check if is is a mov r<type>, r<type> (referenced as nop(type))
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800735 // These instructions are generated to mark special location in the code,
736 // like some special IC code.
737 static inline bool IsMarkedCode(Instr instr, int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800739 return IsNop(instr, type);
740 }
741
742
743 static inline int GetCodeMarker(Instr instr) {
744 int dst_reg_offset = 12;
745 int dst_mask = 0xf << dst_reg_offset;
746 int src_mask = 0xf;
747 int dst_reg = (instr & dst_mask) >> dst_reg_offset;
748 int src_reg = instr & src_mask;
749 uint32_t non_register_mask = ~(dst_mask | src_mask);
750 uint32_t mov_mask = al | 13 << 21;
751
752 // Return <n> if we have a mov rn rn, else return -1.
753 int type = ((instr & non_register_mask) == mov_mask) &&
754 (dst_reg == src_reg) &&
755 (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER)
756 ? src_reg
757 : -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758 DCHECK((type == -1) ||
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800759 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
760 return type;
761 }
762
Steve Blocka7e24c12009-10-30 11:49:00 +0000763
764 // ---------------------------------------------------------------------------
765 // Allocation support
766
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000767 // Allocate an object in new space or old space. The object_size is
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000768 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS
769 // is passed. If the space is exhausted control continues at the gc_required
770 // label. The allocated object is returned in result. If the flag
771 // tag_allocated_object is true the result is tagged as as a heap object.
772 // All registers are clobbered also when control continues at the gc_required
773 // label.
774 void Allocate(int object_size,
775 Register result,
776 Register scratch1,
777 Register scratch2,
778 Label* gc_required,
779 AllocationFlags flags);
780
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 void Allocate(Register object_size, Register result, Register result_end,
782 Register scratch, Label* gc_required, AllocationFlags flags);
Andrei Popescu31002712010-02-23 13:46:05 +0000783
Ben Murdochc5610432016-08-08 18:44:38 +0100784 // FastAllocate is right now only used for folded allocations. It just
785 // increments the top pointer without checking against limit. This can only
786 // be done if it was proved earlier that the allocation will succeed.
787 void FastAllocate(int object_size, Register result, Register scratch1,
788 Register scratch2, AllocationFlags flags);
789
790 void FastAllocate(Register object_size, Register result, Register result_end,
791 Register scratch, AllocationFlags flags);
792
Andrei Popescu31002712010-02-23 13:46:05 +0000793 void AllocateTwoByteString(Register result,
794 Register length,
795 Register scratch1,
796 Register scratch2,
797 Register scratch3,
798 Label* gc_required);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000799 void AllocateOneByteString(Register result, Register length,
800 Register scratch1, Register scratch2,
801 Register scratch3, Label* gc_required);
Andrei Popescu31002712010-02-23 13:46:05 +0000802 void AllocateTwoByteConsString(Register result,
803 Register length,
804 Register scratch1,
805 Register scratch2,
806 Label* gc_required);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000807 void AllocateOneByteConsString(Register result, Register length,
808 Register scratch1, Register scratch2,
809 Label* gc_required);
Ben Murdoch589d6972011-11-30 16:04:58 +0000810 void AllocateTwoByteSlicedString(Register result,
811 Register length,
812 Register scratch1,
813 Register scratch2,
814 Label* gc_required);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000815 void AllocateOneByteSlicedString(Register result, Register length,
816 Register scratch1, Register scratch2,
817 Label* gc_required);
Andrei Popescu31002712010-02-23 13:46:05 +0000818
Kristian Monsen25f61362010-05-21 11:50:48 +0100819 // Allocates a heap number or jumps to the gc_required label if the young
820 // space is full and a scavenge is needed. All registers are clobbered also
821 // when control continues at the gc_required label.
Steve Block6ded16b2010-05-10 14:33:55 +0100822 void AllocateHeapNumber(Register result,
823 Register scratch1,
824 Register scratch2,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100825 Register heap_number_map,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000826 Label* gc_required,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000827 MutableMode mode = IMMUTABLE);
Steve Block8defd9f2010-07-08 12:39:36 +0100828 void AllocateHeapNumberWithValue(Register result,
829 DwVfpRegister value,
830 Register scratch1,
831 Register scratch2,
832 Register heap_number_map,
833 Label* gc_required);
834
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 // Allocate and initialize a JSValue wrapper with the specified {constructor}
836 // and {value}.
837 void AllocateJSValue(Register result, Register constructor, Register value,
838 Register scratch1, Register scratch2,
839 Label* gc_required);
Andrei Popescu31002712010-02-23 13:46:05 +0000840
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100841 // Copies a number of bytes from src to dst. All registers are clobbered. On
842 // exit src and dst will point to the place just after where the last byte was
843 // read or written and length will be zero.
844 void CopyBytes(Register src,
845 Register dst,
846 Register length,
847 Register scratch);
848
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000849 // Initialize fields with filler values. Fields starting at |current_address|
850 // not including |end_address| are overwritten with the value in |filler|. At
851 // the end the loop, |current_address| takes the value of |end_address|.
852 void InitializeFieldsWithFiller(Register current_address,
853 Register end_address, Register filler);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100854
Steve Blocka7e24c12009-10-30 11:49:00 +0000855 // ---------------------------------------------------------------------------
856 // Support functions.
857
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000858 // Machine code version of Map::GetConstructor().
859 // |temp| holds |result|'s map when done, and |temp2| its instance type.
860 void GetMapConstructor(Register result, Register map, Register temp,
861 Register temp2);
862
Steve Blocka7e24c12009-10-30 11:49:00 +0000863 // Try to get function prototype of a function and puts the value in
864 // the result register. Checks that the function really is a
865 // function and jumps to the miss label if the fast checks fail. The
866 // function register will be untouched; the other registers may be
867 // clobbered.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000868 void TryGetFunctionPrototype(Register function, Register result,
869 Register scratch, Label* miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000870
871 // Compare object type for heap object. heap_object contains a non-Smi
872 // whose object type should be compared with the given type. This both
873 // sets the flags and leaves the object type in the type_reg register.
874 // It leaves the map in the map register (unless the type_reg and map register
875 // are the same register). It leaves the heap object in the heap_object
876 // register unless the heap_object register is the same register as one of the
877 // other registers.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878 // Type_reg can be no_reg. In that case ip is used.
Steve Blocka7e24c12009-10-30 11:49:00 +0000879 void CompareObjectType(Register heap_object,
880 Register map,
881 Register type_reg,
882 InstanceType type);
883
884 // Compare instance type in a map. map contains a valid map object whose
885 // object type should be compared with the given type. This both
Ben Murdoch589d6972011-11-30 16:04:58 +0000886 // sets the flags and leaves the object type in the type_reg register.
Steve Blocka7e24c12009-10-30 11:49:00 +0000887 void CompareInstanceType(Register map,
888 Register type_reg,
889 InstanceType type);
890
Andrei Popescu31002712010-02-23 13:46:05 +0000891
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000892 // Check if a map for a JSObject indicates that the object has fast elements.
893 // Jump to the specified label if it does not.
894 void CheckFastElements(Register map,
895 Register scratch,
896 Label* fail);
897
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100898 // Check if a map for a JSObject indicates that the object can have both smi
899 // and HeapObject elements. Jump to the specified label if it does not.
900 void CheckFastObjectElements(Register map,
901 Register scratch,
902 Label* fail);
903
904 // Check if a map for a JSObject indicates that the object has fast smi only
905 // elements. Jump to the specified label if it does not.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 void CheckFastSmiElements(Register map,
907 Register scratch,
908 Label* fail);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100909
910 // Check to see if maybe_number can be stored as a double in
911 // FastDoubleElements. If it can, store it at the index specified by key in
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000912 // the FastDoubleElements array elements. Otherwise jump to fail.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100913 void StoreNumberToDoubleElements(Register value_reg,
914 Register key_reg,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100915 Register elements_reg,
916 Register scratch1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000917 LowDwVfpRegister double_scratch,
918 Label* fail,
919 int elements_offset = 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100920
921 // Compare an object's map with the specified map and its transitioned
922 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are
923 // set with result of map compare. If multiple map compares are required, the
924 // compare sequences branches to early_success.
925 void CompareMap(Register obj,
926 Register scratch,
927 Handle<Map> map,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000928 Label* early_success);
929
930 // As above, but the map of the object is already loaded into the register
931 // which is preserved by the code generated.
932 void CompareMap(Register obj_map,
933 Handle<Map> map,
934 Label* early_success);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100935
936 // Check if the map of an object is equal to a specified map and branch to
937 // label if not. Skip the smi check if not required (object is known to be a
938 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
939 // against maps that are ElementsKind transition maps of the specified map.
Andrei Popescu31002712010-02-23 13:46:05 +0000940 void CheckMap(Register obj,
941 Register scratch,
942 Handle<Map> map,
943 Label* fail,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 SmiCheckType smi_check_type);
Ben Murdoch257744e2011-11-30 15:57:28 +0000945
Andrei Popescu31002712010-02-23 13:46:05 +0000946
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100947 void CheckMap(Register obj,
948 Register scratch,
949 Heap::RootListIndex index,
950 Label* fail,
Ben Murdoch257744e2011-11-30 15:57:28 +0000951 SmiCheckType smi_check_type);
952
953
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400954 // Check if the map of an object is equal to a specified weak map and branch
955 // to a specified target if equal. Skip the smi check if not required
956 // (object is known to be a heap object)
957 void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
958 Handle<WeakCell> cell, Handle<Code> success,
959 SmiCheckType smi_check_type);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100960
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400961 // Compare the given value and the value of weak cell.
962 void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
963
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 void GetWeakValue(Register value, Handle<WeakCell> cell);
965
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400966 // Load the value of the weak cell in the value register. Branch to the given
967 // miss label if the weak cell was cleared.
968 void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100969
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100970 // Compare the object in a register to a value from the root list.
971 // Uses the ip register as scratch.
972 void CompareRoot(Register obj, Heap::RootListIndex index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000973 void PushRoot(Heap::RootListIndex index) {
974 LoadRoot(ip, index);
975 Push(ip);
976 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100977
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000978 // Compare the object in a register to a value and jump if they are equal.
979 void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) {
980 CompareRoot(with, index);
981 b(eq, if_equal);
982 }
983
984 // Compare the object in a register to a value and jump if they are not equal.
985 void JumpIfNotRoot(Register with, Heap::RootListIndex index,
986 Label* if_not_equal) {
987 CompareRoot(with, index);
988 b(ne, if_not_equal);
989 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100990
Andrei Popescu31002712010-02-23 13:46:05 +0000991 // Load and check the instance type of an object for being a string.
992 // Loads the type into the second argument register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000993 // Returns a condition that will be enabled if the object was a string
994 // and the passed-in condition passed. If the passed-in condition failed
995 // then flags remain unchanged.
Andrei Popescu31002712010-02-23 13:46:05 +0000996 Condition IsObjectStringType(Register obj,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000997 Register type,
998 Condition cond = al) {
999 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset), cond);
1000 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset), cond);
1001 tst(type, Operand(kIsNotStringMask), cond);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001002 DCHECK_EQ(0u, kStringTag);
Andrei Popescu31002712010-02-23 13:46:05 +00001003 return eq;
1004 }
1005
1006
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001007 // Picks out an array index from the hash field.
1008 // Register use:
1009 // hash - holds the index's hash. Clobbered.
1010 // index - holds the overwritten index on exit.
1011 void IndexFromHash(Register hash, Register index);
1012
Andrei Popescu31002712010-02-23 13:46:05 +00001013 // Get the number of least significant bits from a register
1014 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
Steve Block1e0659c2011-05-24 12:43:12 +01001015 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits);
Andrei Popescu31002712010-02-23 13:46:05 +00001016
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001017 // Load the value of a smi object into a double register.
1018 // The register value must be between d0 and d15.
1019 void SmiToDouble(LowDwVfpRegister value, Register smi);
Steve Blockd0582a62009-12-15 09:54:21 +00001020
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001021 // Check if a double can be exactly represented as a signed 32-bit integer.
1022 // Z flag set to one if true.
1023 void TestDoubleIsInt32(DwVfpRegister double_input,
1024 LowDwVfpRegister double_scratch);
Steve Block8defd9f2010-07-08 12:39:36 +01001025
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001026 // Try to convert a double to a signed 32-bit integer.
1027 // Z flag set to one and result assigned if the conversion is exact.
1028 void TryDoubleToInt32Exact(Register result,
1029 DwVfpRegister double_input,
1030 LowDwVfpRegister double_scratch);
Steve Block8defd9f2010-07-08 12:39:36 +01001031
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001032 // Floor a double and writes the value to the result register.
1033 // Go to exact if the conversion is exact (to be able to test -0),
1034 // fall through calling code if an overflow occurred, else go to done.
1035 // In return, input_high is loaded with high bits of input.
1036 void TryInt32Floor(Register result,
1037 DwVfpRegister double_input,
1038 Register input_high,
1039 LowDwVfpRegister double_scratch,
1040 Label* done,
1041 Label* exact);
Iain Merrick9ac36c92010-09-13 15:29:50 +01001042
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001043 // Performs a truncating conversion of a floating point number as used by
1044 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
1045 // succeeds, otherwise falls through if result is saturated. On return
1046 // 'result' either holds answer, or is clobbered on fall through.
1047 //
1048 // Only public for the test code in test-code-stubs-arm.cc.
1049 void TryInlineTruncateDoubleToI(Register result,
1050 DwVfpRegister input,
1051 Label* done);
Steve Block44f0eee2011-05-26 01:26:41 +01001052
1053 // Performs a truncating conversion of a floating point number as used by
1054 // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001055 // Exits with 'result' holding the answer.
1056 void TruncateDoubleToI(Register result, DwVfpRegister double_input);
Steve Block44f0eee2011-05-26 01:26:41 +01001057
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001058 // Performs a truncating conversion of a heap number as used by
1059 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input'
1060 // must be different registers. Exits with 'result' holding the answer.
1061 void TruncateHeapNumberToI(Register result, Register object);
1062
1063 // Converts the smi or heap number in object to an int32 using the rules
1064 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
1065 // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be
1066 // different registers.
1067 void TruncateNumberToI(Register object,
1068 Register result,
1069 Register heap_number_map,
1070 Register scratch1,
1071 Label* not_int32);
1072
1073 // Check whether d16-d31 are available on the CPU. The result is given by the
1074 // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise.
1075 void CheckFor32DRegs(Register scratch);
1076
1077 // Does a runtime check for 16/32 FP registers. Either way, pushes 32 double
1078 // values to location, saving [d0..(d15|d31)].
1079 void SaveFPRegs(Register location, Register scratch);
1080
1081 // Does a runtime check for 16/32 FP registers. Either way, pops 32 double
1082 // values to location, restoring [d0..(d15|d31)].
1083 void RestoreFPRegs(Register location, Register scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +00001084
1085 // ---------------------------------------------------------------------------
1086 // Runtime calls
1087
1088 // Call a code stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001089 void CallStub(CodeStub* stub,
1090 TypeFeedbackId ast_id = TypeFeedbackId::None(),
1091 Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +00001092
Andrei Popescu31002712010-02-23 13:46:05 +00001093 // Call a code stub.
1094 void TailCallStub(CodeStub* stub, Condition cond = al);
1095
Steve Blocka7e24c12009-10-30 11:49:00 +00001096 // Call a runtime routine.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001097 void CallRuntime(const Runtime::Function* f,
1098 int num_arguments,
1099 SaveFPRegsMode save_doubles = kDontSaveFPRegs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001100 void CallRuntimeSaveDoubles(Runtime::FunctionId fid) {
1101 const Runtime::Function* function = Runtime::FunctionForId(fid);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001102 CallRuntime(function, function->nargs, kSaveFPRegs);
1103 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001104
1105 // Convenience function: Same as above, but takes the fid instead.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001106 void CallRuntime(Runtime::FunctionId fid,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107 SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001108 const Runtime::Function* function = Runtime::FunctionForId(fid);
1109 CallRuntime(function, function->nargs, save_doubles);
1110 }
1111
1112 // Convenience function: Same as above, but takes the fid instead.
1113 void CallRuntime(Runtime::FunctionId fid, int num_arguments,
1114 SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
1115 CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001116 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001117
Andrei Popescu402d9372010-02-26 13:31:12 +00001118 // Convenience function: call an external reference.
1119 void CallExternalReference(const ExternalReference& ext,
1120 int num_arguments);
1121
Steve Block6ded16b2010-05-10 14:33:55 +01001122 // Convenience function: tail call a runtime routine (jump).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001123 void TailCallRuntime(Runtime::FunctionId fid);
Steve Blocka7e24c12009-10-30 11:49:00 +00001124
Ben Murdoch257744e2011-11-30 15:57:28 +00001125 int CalculateStackPassedWords(int num_reg_arguments,
1126 int num_double_arguments);
1127
Steve Block6ded16b2010-05-10 14:33:55 +01001128 // Before calling a C-function from generated code, align arguments on stack.
1129 // After aligning the frame, non-register arguments must be stored in
1130 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
Ben Murdoch257744e2011-11-30 15:57:28 +00001131 // are word sized. If double arguments are used, this function assumes that
1132 // all double arguments are stored before core registers; otherwise the
1133 // correct alignment of the double values is not guaranteed.
Steve Block6ded16b2010-05-10 14:33:55 +01001134 // Some compilers/platforms require the stack to be aligned when calling
1135 // C++ code.
1136 // Needs a scratch register to do some arithmetic. This register will be
1137 // trashed.
Ben Murdoch257744e2011-11-30 15:57:28 +00001138 void PrepareCallCFunction(int num_reg_arguments,
1139 int num_double_registers,
1140 Register scratch);
1141 void PrepareCallCFunction(int num_reg_arguments,
1142 Register scratch);
1143
1144 // There are two ways of passing double arguments on ARM, depending on
1145 // whether soft or hard floating point ABI is used. These functions
1146 // abstract parameter passing for the three different ways we call
1147 // C functions from generated code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001148 void MovToFloatParameter(DwVfpRegister src);
1149 void MovToFloatParameters(DwVfpRegister src1, DwVfpRegister src2);
1150 void MovToFloatResult(DwVfpRegister src);
Steve Block6ded16b2010-05-10 14:33:55 +01001151
1152 // Calls a C function and cleans up the space for arguments allocated
1153 // by PrepareCallCFunction. The called function is not allowed to trigger a
1154 // garbage collection, since that might move the code and invalidate the
1155 // return address (unless this is somehow accounted for by the called
1156 // function).
1157 void CallCFunction(ExternalReference function, int num_arguments);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001158 void CallCFunction(Register function, int num_arguments);
Ben Murdoch257744e2011-11-30 15:57:28 +00001159 void CallCFunction(ExternalReference function,
1160 int num_reg_arguments,
1161 int num_double_arguments);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001162 void CallCFunction(Register function,
Ben Murdoch257744e2011-11-30 15:57:28 +00001163 int num_reg_arguments,
1164 int num_double_arguments);
Steve Block6ded16b2010-05-10 14:33:55 +01001165
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001166 void MovFromFloatParameter(DwVfpRegister dst);
1167 void MovFromFloatResult(DwVfpRegister dst);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001168
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 // Jump to a runtime routine.
Steve Block6ded16b2010-05-10 14:33:55 +01001170 void JumpToExternalReference(const ExternalReference& builtin);
Steve Blocka7e24c12009-10-30 11:49:00 +00001171
Ben Murdoch8b112d22011-06-08 16:22:53 +01001172 Handle<Object> CodeObject() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001173 DCHECK(!code_object_.is_null());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001174 return code_object_;
1175 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001176
1177
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001178 // Emit code for a truncating division by a constant. The dividend register is
1179 // unchanged and ip gets clobbered. Dividend and result must be different.
1180 void TruncatingDiv(Register result, Register dividend, int32_t divisor);
1181
Steve Blocka7e24c12009-10-30 11:49:00 +00001182 // ---------------------------------------------------------------------------
1183 // StatsCounter support
1184
1185 void SetCounter(StatsCounter* counter, int value,
1186 Register scratch1, Register scratch2);
1187 void IncrementCounter(StatsCounter* counter, int value,
1188 Register scratch1, Register scratch2);
1189 void DecrementCounter(StatsCounter* counter, int value,
1190 Register scratch1, Register scratch2);
1191
1192
1193 // ---------------------------------------------------------------------------
1194 // Debugging
1195
Steve Block1e0659c2011-05-24 12:43:12 +01001196 // Calls Abort(msg) if the condition cond is not satisfied.
Steve Blocka7e24c12009-10-30 11:49:00 +00001197 // Use --debug_code to enable.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001198 void Assert(Condition cond, BailoutReason reason);
Iain Merrick75681382010-08-19 15:07:18 +01001199 void AssertFastElements(Register elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00001200
1201 // Like Assert(), but always enabled.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001202 void Check(Condition cond, BailoutReason reason);
Steve Blocka7e24c12009-10-30 11:49:00 +00001203
1204 // Print a message to stdout and abort execution.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001205 void Abort(BailoutReason msg);
Steve Blocka7e24c12009-10-30 11:49:00 +00001206
1207 // Verify restrictions about code generated in stubs.
1208 void set_generating_stub(bool value) { generating_stub_ = value; }
1209 bool generating_stub() { return generating_stub_; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001210 void set_has_frame(bool value) { has_frame_ = value; }
1211 bool has_frame() { return has_frame_; }
1212 inline bool AllowThisStubCall(CodeStub* stub);
Steve Blocka7e24c12009-10-30 11:49:00 +00001213
Ben Murdoch257744e2011-11-30 15:57:28 +00001214 // EABI variant for double arguments in use.
1215 bool use_eabi_hardfloat() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001216#ifdef __arm__
1217 return base::OS::ArmUsingHardFloat();
1218#elif USE_EABI_HARDFLOAT
Ben Murdoch257744e2011-11-30 15:57:28 +00001219 return true;
1220#else
1221 return false;
1222#endif
1223 }
1224
Leon Clarked91b9f72010-01-27 17:25:45 +00001225 // ---------------------------------------------------------------------------
Steve Block1e0659c2011-05-24 12:43:12 +01001226 // Number utilities
1227
1228 // Check whether the value of reg is a power of two and not zero. If not
1229 // control continues at the label not_power_of_two. If reg is a power of two
1230 // the register scratch contains the value of (reg - 1) when control falls
1231 // through.
1232 void JumpIfNotPowerOfTwoOrZero(Register reg,
1233 Register scratch,
1234 Label* not_power_of_two_or_zero);
Steve Block44f0eee2011-05-26 01:26:41 +01001235 // Check whether the value of reg is a power of two and not zero.
1236 // Control falls through if it is, with scratch containing the mask
1237 // value (reg - 1).
1238 // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is
1239 // zero or negative, or jumps to the 'not_power_of_two' label if the value is
1240 // strictly positive but not a power of two.
1241 void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
1242 Register scratch,
1243 Label* zero_and_neg,
1244 Label* not_power_of_two);
Steve Block1e0659c2011-05-24 12:43:12 +01001245
1246 // ---------------------------------------------------------------------------
Andrei Popescu31002712010-02-23 13:46:05 +00001247 // Smi utilities
1248
Ben Murdochb0fe1622011-05-05 13:52:32 +01001249 void SmiTag(Register reg, SBit s = LeaveCC) {
1250 add(reg, reg, Operand(reg), s);
1251 }
Steve Block1e0659c2011-05-24 12:43:12 +01001252 void SmiTag(Register dst, Register src, SBit s = LeaveCC) {
1253 add(dst, src, Operand(src), s);
1254 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001255
Ben Murdochb8e0da22011-05-16 14:20:40 +01001256 // Try to convert int32 to smi. If the value is to large, preserve
1257 // the original value and jump to not_a_smi. Destroys scratch and
1258 // sets flags.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001259 void TrySmiTag(Register reg, Label* not_a_smi) {
1260 TrySmiTag(reg, reg, not_a_smi);
1261 }
1262 void TrySmiTag(Register reg, Register src, Label* not_a_smi) {
1263 SmiTag(ip, src, SetCC);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001264 b(vs, not_a_smi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001265 mov(reg, ip);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001266 }
1267
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001268
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001269 void SmiUntag(Register reg, SBit s = LeaveCC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001270 mov(reg, Operand::SmiUntag(reg), s);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001271 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001272 void SmiUntag(Register dst, Register src, SBit s = LeaveCC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001273 mov(dst, Operand::SmiUntag(src), s);
Steve Block1e0659c2011-05-24 12:43:12 +01001274 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001275
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001276 // Untag the source value into destination and jump if source is a smi.
1277 // Souce and destination can be the same register.
1278 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case);
1279
1280 // Untag the source value into destination and jump if source is not a smi.
1281 // Souce and destination can be the same register.
1282 void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case);
1283
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001284 // Test if the register contains a smi (Z == 0 (eq) if true).
1285 inline void SmiTst(Register value) {
1286 tst(value, Operand(kSmiTagMask));
1287 }
1288 inline void NonNegativeSmiTst(Register value) {
1289 tst(value, Operand(kSmiTagMask | kSmiSignMask));
1290 }
1291 // Jump if the register contains a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001292 inline void JumpIfSmi(Register value, Label* smi_label) {
1293 tst(value, Operand(kSmiTagMask));
1294 b(eq, smi_label);
1295 }
1296 // Jump if either of the registers contain a non-smi.
1297 inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
1298 tst(value, Operand(kSmiTagMask));
1299 b(ne, not_smi_label);
1300 }
Andrei Popescu31002712010-02-23 13:46:05 +00001301 // Jump if either of the registers contain a non-smi.
1302 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
1303 // Jump if either of the registers contain a smi.
1304 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
1305
Ben Murdochda12d292016-06-02 14:46:10 +01001306 // Abort execution if argument is a number, enabled via --debug-code.
1307 void AssertNotNumber(Register object);
1308
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001309 // Abort execution if argument is a smi, enabled via --debug-code.
1310 void AssertNotSmi(Register object);
1311 void AssertSmi(Register object);
Steve Block1e0659c2011-05-24 12:43:12 +01001312
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001313 // Abort execution if argument is not a string, enabled via --debug-code.
1314 void AssertString(Register object);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001315
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001316 // Abort execution if argument is not a name, enabled via --debug-code.
1317 void AssertName(Register object);
1318
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001319 // Abort execution if argument is not a JSFunction, enabled via --debug-code.
1320 void AssertFunction(Register object);
1321
1322 // Abort execution if argument is not a JSBoundFunction,
1323 // enabled via --debug-code.
1324 void AssertBoundFunction(Register object);
1325
Ben Murdochc5610432016-08-08 18:44:38 +01001326 // Abort execution if argument is not a JSGeneratorObject,
1327 // enabled via --debug-code.
1328 void AssertGeneratorObject(Register object);
1329
Ben Murdoch097c5b22016-05-18 11:27:45 +01001330 // Abort execution if argument is not a JSReceiver, enabled via --debug-code.
1331 void AssertReceiver(Register object);
1332
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001333 // Abort execution if argument is not undefined or an AllocationSite, enabled
1334 // via --debug-code.
1335 void AssertUndefinedOrAllocationSite(Register object, Register scratch);
1336
1337 // Abort execution if reg is not the root value with the given index,
1338 // enabled via --debug-code.
1339 void AssertIsRoot(Register reg, Heap::RootListIndex index);
Steve Block1e0659c2011-05-24 12:43:12 +01001340
1341 // ---------------------------------------------------------------------------
1342 // HeapNumber utilities
1343
1344 void JumpIfNotHeapNumber(Register object,
1345 Register heap_number_map,
1346 Register scratch,
1347 Label* on_not_heap_number);
Iain Merrick75681382010-08-19 15:07:18 +01001348
Andrei Popescu31002712010-02-23 13:46:05 +00001349 // ---------------------------------------------------------------------------
Leon Clarked91b9f72010-01-27 17:25:45 +00001350 // String utilities
1351
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001352 // Checks if both objects are sequential one-byte strings and jumps to label
Leon Clarked91b9f72010-01-27 17:25:45 +00001353 // if either is not. Assumes that neither object is a smi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001354 void JumpIfNonSmisNotBothSequentialOneByteStrings(Register object1,
1355 Register object2,
1356 Register scratch1,
1357 Register scratch2,
1358 Label* failure);
Leon Clarked91b9f72010-01-27 17:25:45 +00001359
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001360 // Checks if both objects are sequential one-byte strings and jumps to label
Leon Clarked91b9f72010-01-27 17:25:45 +00001361 // if either is not.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001362 void JumpIfNotBothSequentialOneByteStrings(Register first, Register second,
1363 Register scratch1,
1364 Register scratch2,
1365 Label* not_flat_one_byte_strings);
Leon Clarked91b9f72010-01-27 17:25:45 +00001366
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001367 // Checks if both instance types are sequential one-byte strings and jumps to
Steve Block6ded16b2010-05-10 14:33:55 +01001368 // label if either is not.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001369 void JumpIfBothInstanceTypesAreNotSequentialOneByte(
1370 Register first_object_instance_type, Register second_object_instance_type,
1371 Register scratch1, Register scratch2, Label* failure);
Steve Block6ded16b2010-05-10 14:33:55 +01001372
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001373 // Check if instance type is sequential one-byte string and jump to label if
Steve Block6ded16b2010-05-10 14:33:55 +01001374 // it is not.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001375 void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch,
1376 Label* failure);
Steve Block6ded16b2010-05-10 14:33:55 +01001377
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378 void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name);
1379
1380 void EmitSeqStringSetCharCheck(Register string,
1381 Register index,
1382 Register value,
1383 uint32_t encoding_mask);
Steve Block6ded16b2010-05-10 14:33:55 +01001384
Steve Block1e0659c2011-05-24 12:43:12 +01001385
Ben Murdoch257744e2011-11-30 15:57:28 +00001386 void ClampUint8(Register output_reg, Register input_reg);
1387
1388 void ClampDoubleToUint8(Register result_reg,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389 DwVfpRegister input_reg,
1390 LowDwVfpRegister double_scratch);
Ben Murdoch257744e2011-11-30 15:57:28 +00001391
1392
1393 void LoadInstanceDescriptors(Register map, Register descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 void EnumLength(Register dst, Register map);
1395 void NumberOfOwnDescriptors(Register dst, Register map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001396 void LoadAccessor(Register dst, Register holder, int accessor_index,
1397 AccessorComponent accessor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398
1399 template<typename Field>
1400 void DecodeField(Register dst, Register src) {
1401 Ubfx(dst, src, Field::kShift, Field::kSize);
1402 }
1403
1404 template<typename Field>
1405 void DecodeField(Register reg) {
1406 DecodeField<Field>(reg, reg);
1407 }
1408
1409 template<typename Field>
1410 void DecodeFieldToSmi(Register dst, Register src) {
1411 static const int shift = Field::kShift;
1412 static const int mask = Field::kMask >> shift << kSmiTagSize;
1413 STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0);
1414 STATIC_ASSERT(kSmiTag == 0);
1415 if (shift < kSmiTagSize) {
1416 mov(dst, Operand(src, LSL, kSmiTagSize - shift));
1417 and_(dst, dst, Operand(mask));
1418 } else if (shift > kSmiTagSize) {
1419 mov(dst, Operand(src, LSR, shift - kSmiTagSize));
1420 and_(dst, dst, Operand(mask));
1421 } else {
1422 and_(dst, src, Operand(mask));
1423 }
1424 }
1425
1426 template<typename Field>
1427 void DecodeFieldToSmi(Register reg) {
1428 DecodeField<Field>(reg, reg);
1429 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001430
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001431 // Load the type feedback vector from a JavaScript frame.
1432 void EmitLoadTypeFeedbackVector(Register vector);
1433
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001434 // Activation support.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001435 void EnterFrame(StackFrame::Type type,
1436 bool load_constant_pool_pointer_reg = false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001437 // Returns the pc offset at which the frame ends.
1438 int LeaveFrame(StackFrame::Type type);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001439
1440 // Expects object in r0 and returns map with validated enum cache
1441 // in r0. Assumes that any other register can be used as a scratch.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001442 void CheckEnumCache(Label* call_runtime);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001443
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001444 // AllocationMemento support. Arrays may have an associated
1445 // AllocationMemento object that can be checked for in order to pretransition
1446 // to another type.
1447 // On entry, receiver_reg should point to the array object.
1448 // scratch_reg gets clobbered.
1449 // If allocation info is present, condition flags are set to eq.
1450 void TestJSArrayForAllocationMemento(Register receiver_reg,
1451 Register scratch_reg,
1452 Label* no_memento_found);
1453
1454 void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
1455 Register scratch_reg,
1456 Label* memento_found) {
1457 Label no_memento_found;
1458 TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
1459 &no_memento_found);
1460 b(eq, memento_found);
1461 bind(&no_memento_found);
1462 }
1463
1464 // Jumps to found label if a prototype map has dictionary elements.
1465 void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
1466 Register scratch1, Label* found);
1467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001468 // Loads the constant pool pointer (pp) register.
1469 void LoadConstantPoolPointerRegisterFromCodeTargetAddress(
1470 Register code_target_address);
1471 void LoadConstantPoolPointerRegister();
1472
Steve Blocka7e24c12009-10-30 11:49:00 +00001473 private:
Steve Block44f0eee2011-05-26 01:26:41 +01001474 void CallCFunctionHelper(Register function,
Ben Murdoch257744e2011-11-30 15:57:28 +00001475 int num_reg_arguments,
1476 int num_double_arguments);
Steve Block44f0eee2011-05-26 01:26:41 +01001477
Andrei Popescu31002712010-02-23 13:46:05 +00001478 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
Steve Blocka7e24c12009-10-30 11:49:00 +00001479
1480 // Helper functions for generating invokes.
1481 void InvokePrologue(const ParameterCount& expected,
1482 const ParameterCount& actual,
Steve Blocka7e24c12009-10-30 11:49:00 +00001483 Label* done,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001484 bool* definitely_mismatches,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001485 InvokeFlag flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001486 const CallWrapper& call_wrapper);
Steve Blocka7e24c12009-10-30 11:49:00 +00001487
Steve Block6ded16b2010-05-10 14:33:55 +01001488 void InitializeNewString(Register string,
1489 Register length,
1490 Heap::RootListIndex map_index,
1491 Register scratch1,
1492 Register scratch2);
1493
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001494 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
1495 void InNewSpace(Register object,
1496 Register scratch,
1497 Condition cond, // eq for new space, ne otherwise.
1498 Label* branch);
1499
1500 // Helper for finding the mark bits for an address. Afterwards, the
1501 // bitmap register points at the word with the mark bits and the mask
1502 // the position of the first bit. Leaves addr_reg unchanged.
1503 inline void GetMarkBits(Register addr_reg,
1504 Register bitmap_reg,
1505 Register mask_reg);
1506
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001507 // Compute memory operands for safepoint stack slots.
1508 static int SafepointRegisterStackIndex(int reg_code);
1509 MemOperand SafepointRegisterSlot(Register reg);
1510 MemOperand SafepointRegistersAndDoublesSlot(Register reg);
1511
Andrei Popescu31002712010-02-23 13:46:05 +00001512 bool generating_stub_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001513 bool has_frame_;
Andrei Popescu31002712010-02-23 13:46:05 +00001514 // This handle will be patched with the code object on installation.
1515 Handle<Object> code_object_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001516
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517 // Needs access to SafepointRegisterStackIndex for compiled frame
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001518 // traversal.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519 friend class StandardFrame;
Steve Blocka7e24c12009-10-30 11:49:00 +00001520};
1521
1522
Steve Blocka7e24c12009-10-30 11:49:00 +00001523// The code patcher is used to patch (typically) small parts of code e.g. for
1524// debugging and other types of instrumentation. When using the code patcher
1525// the exact number of bytes specified must be emitted. It is not legal to emit
1526// relocation information. If any of these constraints are violated it causes
1527// an assertion to fail.
1528class CodePatcher {
1529 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001530 enum FlushICache {
1531 FLUSH,
1532 DONT_FLUSH
1533 };
1534
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001535 CodePatcher(Isolate* isolate, byte* address, int instructions,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001536 FlushICache flush_cache = FLUSH);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001537 ~CodePatcher();
Steve Blocka7e24c12009-10-30 11:49:00 +00001538
1539 // Macro assembler to emit code.
1540 MacroAssembler* masm() { return &masm_; }
1541
1542 // Emit an instruction directly.
Steve Block1e0659c2011-05-24 12:43:12 +01001543 void Emit(Instr instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001544
1545 // Emit an address directly.
1546 void Emit(Address addr);
1547
Steve Block1e0659c2011-05-24 12:43:12 +01001548 // Emit the condition part of an instruction leaving the rest of the current
1549 // instruction unchanged.
1550 void EmitCondition(Condition cond);
1551
Steve Blocka7e24c12009-10-30 11:49:00 +00001552 private:
1553 byte* address_; // The address of the code being patched.
Steve Blocka7e24c12009-10-30 11:49:00 +00001554 int size_; // Number of bytes of the expected patch size.
1555 MacroAssembler masm_; // Macro assembler used to generate the code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001556 FlushICache flush_cache_; // Whether to flush the I cache after patching.
Steve Blocka7e24c12009-10-30 11:49:00 +00001557};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001558
1559
Steve Blocka7e24c12009-10-30 11:49:00 +00001560// -----------------------------------------------------------------------------
1561// Static helper functions.
1562
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001563inline MemOperand ContextMemOperand(Register context, int index = 0) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001564 return MemOperand(context, Context::SlotOffset(index));
1565}
1566
1567
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001568inline MemOperand NativeContextMemOperand() {
1569 return ContextMemOperand(cp, Context::NATIVE_CONTEXT_INDEX);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001570}
1571
1572
Steve Blocka7e24c12009-10-30 11:49:00 +00001573#ifdef GENERATED_CODE_COVERAGE
1574#define CODE_COVERAGE_STRINGIFY(x) #x
1575#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1576#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1577#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
1578#else
1579#define ACCESS_MASM(masm) masm->
1580#endif
1581
1582
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001583} // namespace internal
1584} // namespace v8
Steve Blocka7e24c12009-10-30 11:49:00 +00001585
1586#endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_