OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 18 matching lines...) Expand all Loading... |
29 #define V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ | 29 #define V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ |
30 | 30 |
31 #include "assembler.h" | 31 #include "assembler.h" |
32 #include "mips/assembler-mips.h" | 32 #include "mips/assembler-mips.h" |
33 | 33 |
34 namespace v8 { | 34 namespace v8 { |
35 namespace internal { | 35 namespace internal { |
36 | 36 |
37 // Forward declaration. | 37 // Forward declaration. |
38 class JumpTarget; | 38 class JumpTarget; |
| 39 class PostCallGenerator; |
39 | 40 |
40 // Register at is used for instruction generation. So it is not safe to use it | 41 // Reserved Register Usage Summary. |
41 // unless we know exactly what we do. | 42 // |
| 43 // Registers t8, t9, and at are reserved for use by the MacroAssembler. |
| 44 // |
| 45 // The programmer should know that the MacroAssembler may clobber these three, |
| 46 // but won't touch other registers except in special cases. |
| 47 // |
| 48 // Per the MIPS ABI, register t9 must be used for indirect function call |
| 49 // via 'jalr t9' or 'jr t9' instructions. This is relied upon by gcc when |
| 50 // trying to update gp register for position-independent-code. Whenever |
| 51 // MIPS generated code calls C code, it must be via t9 register. |
42 | 52 |
43 // Registers aliases | 53 // Registers aliases |
44 // cp is assumed to be a callee saved register. | 54 // cp is assumed to be a callee saved register. |
| 55 const Register roots = s6; // Roots array pointer. |
45 const Register cp = s7; // JavaScript context pointer | 56 const Register cp = s7; // JavaScript context pointer |
46 const Register fp = s8_fp; // Alias fp | 57 const Register fp = s8_fp; // Alias fp |
| 58 // Register used for condition evaluation. |
| 59 const Register condReg1 = s4; |
| 60 const Register condReg2 = s5; |
47 | 61 |
48 enum InvokeJSFlags { | 62 enum InvokeJSFlags { |
49 CALL_JS, | 63 CALL_JS, |
50 JUMP_JS | 64 JUMP_JS |
51 }; | 65 }; |
52 | 66 |
| 67 |
| 68 // Flags used for the AllocateInNewSpace functions. |
| 69 enum AllocationFlags { |
| 70 // No special flags. |
| 71 NO_ALLOCATION_FLAGS = 0, |
| 72 // Return the pointer to the allocated already tagged as a heap object. |
| 73 TAG_OBJECT = 1 << 0, |
| 74 // The content of the result register already contains the allocation top in |
| 75 // new space. |
| 76 RESULT_CONTAINS_TOP = 1 << 1, |
| 77 // Specify that the requested size of the space to allocate is specified in |
| 78 // words instead of bytes. |
| 79 SIZE_IN_WORDS = 1 << 2 |
| 80 }; |
| 81 |
| 82 // Flags used for the ObjectToDoubleFPURegister function. |
| 83 enum ObjectToDoubleFlags { |
| 84 // No special flags. |
| 85 NO_OBJECT_TO_DOUBLE_FLAGS = 0, |
| 86 // Object is known to be a non smi. |
| 87 OBJECT_NOT_SMI = 1 << 0, |
| 88 // Don't load NaNs or infinities, branch to the non number case instead. |
| 89 AVOID_NANS_AND_INFINITIES = 1 << 1 |
| 90 }; |
| 91 |
| 92 // Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls. |
| 93 enum BranchDelaySlot { |
| 94 USE_DELAY_SLOT, |
| 95 PROTECT |
| 96 }; |
| 97 |
53 // MacroAssembler implements a collection of frequently used macros. | 98 // MacroAssembler implements a collection of frequently used macros. |
54 class MacroAssembler: public Assembler { | 99 class MacroAssembler: public Assembler { |
55 public: | 100 public: |
56 MacroAssembler(void* buffer, int size); | 101 MacroAssembler(void* buffer, int size); |
57 | 102 |
58 // Jump, Call, and Ret pseudo instructions implementing inter-working. | 103 // Arguments macros |
59 void Jump(const Operand& target, | 104 #define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2 |
60 Condition cond = cc_always, | 105 #define COND_ARGS cond, r1, r2 |
61 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 106 |
62 void Call(const Operand& target, | 107 // ** Prototypes |
63 Condition cond = cc_always, | 108 |
64 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 109 // * Prototypes for functions with no target (eg Ret()). |
65 void Jump(Register target, | 110 #define DECLARE_NOTARGET_PROTOTYPE(Name) \ |
66 Condition cond = cc_always, | 111 void Name(BranchDelaySlot bd = PROTECT); \ |
67 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 112 void Name(COND_TYPED_ARGS, BranchDelaySlot bd = PROTECT); \ |
68 void Jump(byte* target, RelocInfo::Mode rmode, | 113 inline void Name(BranchDelaySlot bd, COND_TYPED_ARGS) { \ |
69 Condition cond = cc_always, | 114 Name(COND_ARGS, bd); \ |
70 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 115 } |
71 void Jump(Handle<Code> code, RelocInfo::Mode rmode, | 116 |
72 Condition cond = cc_always, | 117 // * Prototypes for functions with a target. |
73 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 118 |
74 void Call(Register target, | 119 // Cases when relocation may be needed. |
75 Condition cond = cc_always, | 120 #define DECLARE_RELOC_PROTOTYPE(Name, target_type) \ |
76 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 121 void Name(target_type target, \ |
77 void Call(byte* target, RelocInfo::Mode rmode, | 122 RelocInfo::Mode rmode, \ |
78 Condition cond = cc_always, | 123 BranchDelaySlot bd = PROTECT); \ |
79 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 124 inline void Name(BranchDelaySlot bd, \ |
80 void Call(Handle<Code> code, RelocInfo::Mode rmode, | 125 target_type target, \ |
81 Condition cond = cc_always, | 126 RelocInfo::Mode rmode) { \ |
82 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 127 Name(target, rmode, bd); \ |
83 void Ret(Condition cond = cc_always, | 128 } \ |
84 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 129 void Name(target_type target, \ |
85 void Branch(Condition cond, int16_t offset, Register rs = zero_reg, | 130 RelocInfo::Mode rmode, \ |
86 const Operand& rt = Operand(zero_reg), Register scratch = at); | 131 COND_TYPED_ARGS, \ |
87 void Branch(Condition cond, Label* L, Register rs = zero_reg, | 132 BranchDelaySlot bd = PROTECT); \ |
88 const Operand& rt = Operand(zero_reg), Register scratch = at); | 133 inline void Name(BranchDelaySlot bd, \ |
89 // conditionnal branch and link | 134 target_type target, \ |
90 void BranchAndLink(Condition cond, int16_t offset, Register rs = zero_reg, | 135 RelocInfo::Mode rmode, \ |
91 const Operand& rt = Operand(zero_reg), | 136 COND_TYPED_ARGS) { \ |
92 Register scratch = at); | 137 Name(target, rmode, COND_ARGS, bd); \ |
93 void BranchAndLink(Condition cond, Label* L, Register rs = zero_reg, | 138 } |
94 const Operand& rt = Operand(zero_reg), | 139 |
95 Register scratch = at); | 140 // Cases when relocation is not needed. |
| 141 #define DECLARE_NORELOC_PROTOTYPE(Name, target_type) \ |
| 142 void Name(target_type target, BranchDelaySlot bd = PROTECT); \ |
| 143 inline void Name(BranchDelaySlot bd, target_type target) { \ |
| 144 Name(target, bd); \ |
| 145 } \ |
| 146 void Name(target_type target, \ |
| 147 COND_TYPED_ARGS, \ |
| 148 BranchDelaySlot bd = PROTECT); \ |
| 149 inline void Name(BranchDelaySlot bd, \ |
| 150 target_type target, \ |
| 151 COND_TYPED_ARGS) { \ |
| 152 Name(target, COND_ARGS, bd); \ |
| 153 } |
| 154 |
| 155 // ** Target prototypes. |
| 156 |
| 157 #define DECLARE_JUMP_CALL_PROTOTYPES(Name) \ |
| 158 DECLARE_NORELOC_PROTOTYPE(Name, Register) \ |
| 159 DECLARE_NORELOC_PROTOTYPE(Name, const Operand&) \ |
| 160 DECLARE_RELOC_PROTOTYPE(Name, byte*) \ |
| 161 DECLARE_RELOC_PROTOTYPE(Name, Handle<Code>) |
| 162 |
| 163 #define DECLARE_BRANCH_PROTOTYPES(Name) \ |
| 164 DECLARE_NORELOC_PROTOTYPE(Name, Label*) \ |
| 165 DECLARE_NORELOC_PROTOTYPE(Name, int16_t) |
| 166 |
| 167 |
| 168 DECLARE_JUMP_CALL_PROTOTYPES(Jump) |
| 169 DECLARE_JUMP_CALL_PROTOTYPES(Call) |
| 170 |
| 171 DECLARE_BRANCH_PROTOTYPES(Branch) |
| 172 DECLARE_BRANCH_PROTOTYPES(BranchAndLink) |
| 173 |
| 174 DECLARE_NOTARGET_PROTOTYPE(Ret) |
| 175 |
| 176 #undef COND_TYPED_ARGS |
| 177 #undef COND_ARGS |
| 178 #undef DECLARE_NOTARGET_PROTOTYPE |
| 179 #undef DECLARE_NORELOC_PROTOTYPE |
| 180 #undef DECLARE_RELOC_PROTOTYPE |
| 181 #undef DECLARE_JUMP_CALL_PROTOTYPES |
| 182 #undef DECLARE_BRANCH_PROTOTYPES |
96 | 183 |
97 // Emit code to discard a non-negative number of pointer-sized elements | 184 // Emit code to discard a non-negative number of pointer-sized elements |
98 // from the stack, clobbering only the sp register. | 185 // from the stack, clobbering only the sp register. |
99 void Drop(int count, Condition cond = cc_always); | 186 void Drop(int count, |
| 187 Condition cond = cc_always, |
| 188 Register reg = no_reg, |
| 189 const Operand& op = Operand(no_reg)); |
| 190 |
| 191 void DropAndRet(int drop = 0, |
| 192 Condition cond = cc_always, |
| 193 Register reg = no_reg, |
| 194 const Operand& op = Operand(no_reg)); |
| 195 |
| 196 // Swap two registers. If the scratch register is omitted then a slightly |
| 197 // less efficient form using xor instead of mov is emitted. |
| 198 void Swap(Register reg1, Register reg2, Register scratch = no_reg); |
100 | 199 |
101 void Call(Label* target); | 200 void Call(Label* target); |
| 201 // May do nothing if the registers are identical. |
| 202 void Move(Register dst, Register src); |
| 203 |
102 | 204 |
103 // Jump unconditionally to given label. | 205 // Jump unconditionally to given label. |
104 // We NEED a nop in the branch delay slot, as it used by v8, for example in | 206 // We NEED a nop in the branch delay slot, as it used by v8, for example in |
105 // CodeGenerator::ProcessDeferred(). | 207 // CodeGenerator::ProcessDeferred(). |
106 // Currently the branch delay slot is filled by the MacroAssembler. | 208 // Currently the branch delay slot is filled by the MacroAssembler. |
107 // Use rather b(Label) for code generation. | 209 // Use rather b(Label) for code generation. |
108 void jmp(Label* L) { | 210 void jmp(Label* L) { |
109 Branch(cc_always, L); | 211 Branch(L); |
110 } | 212 } |
111 | 213 |
112 // Load an object from the root table. | 214 // Load an object from the root table. |
113 void LoadRoot(Register destination, | 215 void LoadRoot(Register destination, |
114 Heap::RootListIndex index); | 216 Heap::RootListIndex index); |
115 void LoadRoot(Register destination, | 217 void LoadRoot(Register destination, |
116 Heap::RootListIndex index, | 218 Heap::RootListIndex index, |
117 Condition cond, Register src1, const Operand& src2); | 219 Condition cond, Register src1, const Operand& src2); |
118 | 220 |
119 // Load an external reference. | 221 // Store an object to the root table. |
120 void LoadExternalReference(Register reg, ExternalReference ext) { | 222 void StoreRoot(Register source, |
121 li(reg, Operand(ext)); | 223 Heap::RootListIndex index); |
| 224 void StoreRoot(Register source, |
| 225 Heap::RootListIndex index, |
| 226 Condition cond, Register src1, const Operand& src2); |
| 227 |
| 228 |
| 229 // Check if object is in new space. |
| 230 // scratch can be object itself, but it will be clobbered. |
| 231 void InNewSpace(Register object, |
| 232 Register scratch, |
| 233 Condition cc, // eq for new space, ne otherwise. |
| 234 Label* branch); |
| 235 |
| 236 |
| 237 // For the page containing |object| mark the region covering [address] |
| 238 // dirty. The object address must be in the first 8K of an allocated page. |
| 239 void RecordWriteHelper(Register object, |
| 240 Register address, |
| 241 Register scratch); |
| 242 |
| 243 // For the page containing |object| mark the region covering |
| 244 // [object+offset] dirty. The object address must be in the first 8K |
| 245 // of an allocated page. The 'scratch' registers are used in the |
| 246 // implementation and all 3 registers are clobbered by the |
| 247 // operation, as well as the 'at' register. RecordWrite updates the |
| 248 // write barrier even when storing smis. |
| 249 void RecordWrite(Register object, |
| 250 Operand offset, |
| 251 Register scratch0, |
| 252 Register scratch1); |
| 253 |
| 254 // For the page containing |object| mark the region covering |
| 255 // [address] dirty. The object address must be in the first 8K of an |
| 256 // allocated page. All 3 registers are clobbered by the operation, |
| 257 // as well as the ip register. RecordWrite updates the write barrier |
| 258 // even when storing smis. |
| 259 void RecordWrite(Register object, |
| 260 Register address, |
| 261 Register scratch); |
| 262 |
| 263 |
| 264 // --------------------------------------------------------------------------- |
| 265 // Inline caching support |
| 266 |
| 267 // Generate code for checking access rights - used for security checks |
| 268 // on access to global objects across environments. The holder register |
| 269 // is left untouched, whereas both scratch registers are clobbered. |
| 270 void CheckAccessGlobalProxy(Register holder_reg, |
| 271 Register scratch, |
| 272 Label* miss); |
| 273 |
| 274 inline void MarkCode(NopMarkerTypes type) { |
| 275 nop(type); |
122 } | 276 } |
123 | 277 |
124 // Sets the remembered set bit for [address+offset]. | 278 // Check if the given instruction is a 'type' marker. |
125 void RecordWrite(Register object, Register offset, Register scratch); | 279 // ie. check if it is a sll zero_reg, zero_reg, <type> (referenced as |
| 280 // nop(type)). These instructions are generated to mark special location in |
| 281 // the code, like some special IC code. |
| 282 static inline bool IsMarkedCode(Instr instr, int type) { |
| 283 ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)); |
| 284 return IsNop(instr, type); |
| 285 } |
126 | 286 |
127 | 287 |
| 288 static inline int GetCodeMarker(Instr instr) { |
| 289 uint32_t opcode = ((instr & kOpcodeMask)); |
| 290 uint32_t rt = ((instr & kRtFieldMask) >> kRtShift); |
| 291 uint32_t rs = ((instr & kRsFieldMask) >> kRsShift); |
| 292 uint32_t sa = ((instr & kSaFieldMask) >> kSaShift); |
| 293 |
| 294 // Return <n> if we have a sll zero_reg, zero_reg, n |
| 295 // else return -1. |
| 296 bool sllzz = (opcode == SLL && |
| 297 rt == static_cast<uint32_t>(ToNumber(zero_reg)) && |
| 298 rs == static_cast<uint32_t>(ToNumber(zero_reg))); |
| 299 int type = |
| 300 (sllzz && FIRST_IC_MARKER <= sa && sa < LAST_CODE_MARKER) ? sa : -1; |
| 301 ASSERT((type == -1) || |
| 302 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER))); |
| 303 return type; |
| 304 } |
| 305 |
| 306 |
| 307 |
| 308 // --------------------------------------------------------------------------- |
| 309 // Allocation support |
| 310 |
| 311 // Allocate an object in new space. The object_size is specified |
| 312 // either in bytes or in words if the allocation flag SIZE_IN_WORDS |
| 313 // is passed. If the new space is exhausted control continues at the |
| 314 // gc_required label. The allocated object is returned in result. If |
| 315 // the flag tag_allocated_object is true the result is tagged as as |
| 316 // a heap object. All registers are clobbered also when control |
| 317 // continues at the gc_required label. |
| 318 void AllocateInNewSpace(int object_size, |
| 319 Register result, |
| 320 Register scratch1, |
| 321 Register scratch2, |
| 322 Label* gc_required, |
| 323 AllocationFlags flags); |
| 324 void AllocateInNewSpace(Register object_size, |
| 325 Register result, |
| 326 Register scratch1, |
| 327 Register scratch2, |
| 328 Label* gc_required, |
| 329 AllocationFlags flags); |
| 330 |
| 331 // Undo allocation in new space. The object passed and objects allocated after |
| 332 // it will no longer be allocated. The caller must make sure that no pointers |
| 333 // are left to the object(s) no longer allocated as they would be invalid when |
| 334 // allocation is undone. |
| 335 void UndoAllocationInNewSpace(Register object, Register scratch); |
| 336 |
| 337 |
| 338 void AllocateTwoByteString(Register result, |
| 339 Register length, |
| 340 Register scratch1, |
| 341 Register scratch2, |
| 342 Register scratch3, |
| 343 Label* gc_required); |
| 344 void AllocateAsciiString(Register result, |
| 345 Register length, |
| 346 Register scratch1, |
| 347 Register scratch2, |
| 348 Register scratch3, |
| 349 Label* gc_required); |
| 350 void AllocateTwoByteConsString(Register result, |
| 351 Register length, |
| 352 Register scratch1, |
| 353 Register scratch2, |
| 354 Label* gc_required); |
| 355 void AllocateAsciiConsString(Register result, |
| 356 Register length, |
| 357 Register scratch1, |
| 358 Register scratch2, |
| 359 Label* gc_required); |
| 360 |
| 361 // Allocates a heap number or jumps to the gc_required label if the young |
| 362 // space is full and a scavenge is needed. All registers are clobbered also |
| 363 // when control continues at the gc_required label. |
| 364 void AllocateHeapNumber(Register result, |
| 365 Register scratch1, |
| 366 Register scratch2, |
| 367 Register heap_number_map, |
| 368 Label* gc_required); |
| 369 void AllocateHeapNumberWithValue(Register result, |
| 370 FPURegister value, |
| 371 Register scratch1, |
| 372 Register scratch2, |
| 373 Label* gc_required); |
| 374 |
128 // --------------------------------------------------------------------------- | 375 // --------------------------------------------------------------------------- |
129 // Instruction macros | 376 // Instruction macros |
130 | 377 |
131 #define DEFINE_INSTRUCTION(instr) \ | 378 #define DEFINE_INSTRUCTION(instr) \ |
132 void instr(Register rd, Register rs, const Operand& rt); \ | 379 void instr(Register rd, Register rs, const Operand& rt); \ |
133 void instr(Register rd, Register rs, Register rt) { \ | 380 void instr(Register rd, Register rs, Register rt) { \ |
134 instr(rd, rs, Operand(rt)); \ | 381 instr(rd, rs, Operand(rt)); \ |
135 } \ | 382 } \ |
136 void instr(Register rs, Register rt, int32_t j) { \ | 383 void instr(Register rs, Register rt, int32_t j) { \ |
137 instr(rs, rt, Operand(j)); \ | 384 instr(rs, rt, Operand(j)); \ |
138 } | 385 } |
139 | 386 |
140 #define DEFINE_INSTRUCTION2(instr) \ | 387 #define DEFINE_INSTRUCTION2(instr) \ |
141 void instr(Register rs, const Operand& rt); \ | 388 void instr(Register rs, const Operand& rt); \ |
142 void instr(Register rs, Register rt) { \ | 389 void instr(Register rs, Register rt) { \ |
143 instr(rs, Operand(rt)); \ | 390 instr(rs, Operand(rt)); \ |
144 } \ | 391 } \ |
145 void instr(Register rs, int32_t j) { \ | 392 void instr(Register rs, int32_t j) { \ |
146 instr(rs, Operand(j)); \ | 393 instr(rs, Operand(j)); \ |
147 } | 394 } |
148 | 395 |
149 DEFINE_INSTRUCTION(Add); | |
150 DEFINE_INSTRUCTION(Addu); | 396 DEFINE_INSTRUCTION(Addu); |
| 397 DEFINE_INSTRUCTION(Subu); |
151 DEFINE_INSTRUCTION(Mul); | 398 DEFINE_INSTRUCTION(Mul); |
152 DEFINE_INSTRUCTION2(Mult); | 399 DEFINE_INSTRUCTION2(Mult); |
153 DEFINE_INSTRUCTION2(Multu); | 400 DEFINE_INSTRUCTION2(Multu); |
154 DEFINE_INSTRUCTION2(Div); | 401 DEFINE_INSTRUCTION2(Div); |
155 DEFINE_INSTRUCTION2(Divu); | 402 DEFINE_INSTRUCTION2(Divu); |
156 | 403 |
157 DEFINE_INSTRUCTION(And); | 404 DEFINE_INSTRUCTION(And); |
158 DEFINE_INSTRUCTION(Or); | 405 DEFINE_INSTRUCTION(Or); |
159 DEFINE_INSTRUCTION(Xor); | 406 DEFINE_INSTRUCTION(Xor); |
160 DEFINE_INSTRUCTION(Nor); | 407 DEFINE_INSTRUCTION(Nor); |
161 | 408 |
162 DEFINE_INSTRUCTION(Slt); | 409 DEFINE_INSTRUCTION(Slt); |
163 DEFINE_INSTRUCTION(Sltu); | 410 DEFINE_INSTRUCTION(Sltu); |
164 | 411 |
| 412 // MIPS32 R2 instruction macro. |
| 413 DEFINE_INSTRUCTION(Ror); |
| 414 |
165 #undef DEFINE_INSTRUCTION | 415 #undef DEFINE_INSTRUCTION |
166 #undef DEFINE_INSTRUCTION2 | 416 #undef DEFINE_INSTRUCTION2 |
167 | 417 |
168 | 418 |
169 //------------Pseudo-instructions------------- | 419 //------------Pseudo-instructions------------- |
170 | 420 |
171 void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); } | 421 void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); } |
172 // Move the logical ones complement of source to dest. | |
173 void movn(Register rd, Register rt); | |
174 | 422 |
175 | 423 |
176 // load int32 in the rd register | 424 // load int32 in the rd register |
177 void li(Register rd, Operand j, bool gen2instr = false); | 425 void li(Register rd, Operand j, bool gen2instr = false); |
178 inline void li(Register rd, int32_t j, bool gen2instr = false) { | 426 inline void li(Register rd, int32_t j, bool gen2instr = false) { |
179 li(rd, Operand(j), gen2instr); | 427 li(rd, Operand(j), gen2instr); |
180 } | 428 } |
| 429 inline void li(Register dst, Handle<Object> value, bool gen2instr = false) { |
| 430 li(dst, Operand(value), gen2instr); |
| 431 } |
181 | 432 |
182 // Exception-generating instructions and debugging support | 433 // Exception-generating instructions and debugging support |
183 void stop(const char* msg); | 434 void stop(const char* msg); |
184 | 435 |
185 | 436 |
186 // Push multiple registers on the stack. | 437 // Push multiple registers on the stack. |
187 // Registers are saved in numerical order, with higher numbered registers | 438 // Registers are saved in numerical order, with higher numbered registers |
188 // saved in higher memory addresses | 439 // saved in higher memory addresses |
189 void MultiPush(RegList regs); | 440 void MultiPush(RegList regs); |
190 void MultiPushReversed(RegList regs); | 441 void MultiPushReversed(RegList regs); |
| 442 |
191 void Push(Register src) { | 443 void Push(Register src) { |
192 Addu(sp, sp, Operand(-kPointerSize)); | 444 Addu(sp, sp, Operand(-kPointerSize)); |
193 sw(src, MemOperand(sp, 0)); | 445 sw(src, MemOperand(sp, 0)); |
194 } | 446 } |
| 447 |
| 448 // Push two registers. Pushes leftmost register first (to highest address). |
| 449 void Push(Register src1, Register src2, Condition cond = al) { |
| 450 ASSERT(cond == al); // Do not support conditional versions yet. |
| 451 Subu(sp, sp, Operand(2 * kPointerSize)); |
| 452 sw(src1, MemOperand(sp, 1 * kPointerSize)); |
| 453 sw(src2, MemOperand(sp, 0 * kPointerSize)); |
| 454 } |
| 455 |
| 456 // Push three registers. Pushes leftmost register first (to highest address). |
| 457 void Push(Register src1, Register src2, Register src3, Condition cond = al) { |
| 458 ASSERT(cond == al); // Do not support conditional versions yet. |
| 459 Addu(sp, sp, Operand(3 * -kPointerSize)); |
| 460 sw(src1, MemOperand(sp, 2 * kPointerSize)); |
| 461 sw(src2, MemOperand(sp, 1 * kPointerSize)); |
| 462 sw(src3, MemOperand(sp, 0 * kPointerSize)); |
| 463 } |
| 464 |
| 465 // Push four registers. Pushes leftmost register first (to highest address). |
| 466 void Push(Register src1, Register src2, |
| 467 Register src3, Register src4, Condition cond = al) { |
| 468 ASSERT(cond == al); // Do not support conditional versions yet. |
| 469 Addu(sp, sp, Operand(4 * -kPointerSize)); |
| 470 sw(src1, MemOperand(sp, 3 * kPointerSize)); |
| 471 sw(src2, MemOperand(sp, 2 * kPointerSize)); |
| 472 sw(src3, MemOperand(sp, 1 * kPointerSize)); |
| 473 sw(src4, MemOperand(sp, 0 * kPointerSize)); |
| 474 } |
| 475 |
195 inline void push(Register src) { Push(src); } | 476 inline void push(Register src) { Push(src); } |
| 477 inline void pop(Register src) { Pop(src); } |
196 | 478 |
197 void Push(Register src, Condition cond, Register tst1, Register tst2) { | 479 void Push(Register src, Condition cond, Register tst1, Register tst2) { |
198 // Since we don't have conditionnal execution we use a Branch. | 480 // Since we don't have conditionnal execution we use a Branch. |
199 Branch(cond, 3, tst1, Operand(tst2)); | 481 Branch(3, cond, tst1, Operand(tst2)); |
200 Addu(sp, sp, Operand(-kPointerSize)); | 482 Addu(sp, sp, Operand(-kPointerSize)); |
201 sw(src, MemOperand(sp, 0)); | 483 sw(src, MemOperand(sp, 0)); |
202 } | 484 } |
203 | 485 |
| 486 |
204 // Pops multiple values from the stack and load them in the | 487 // Pops multiple values from the stack and load them in the |
205 // registers specified in regs. Pop order is the opposite as in MultiPush. | 488 // registers specified in regs. Pop order is the opposite as in MultiPush. |
206 void MultiPop(RegList regs); | 489 void MultiPop(RegList regs); |
207 void MultiPopReversed(RegList regs); | 490 void MultiPopReversed(RegList regs); |
208 void Pop(Register dst) { | 491 void Pop(Register dst) { |
209 lw(dst, MemOperand(sp, 0)); | 492 lw(dst, MemOperand(sp, 0)); |
210 Addu(sp, sp, Operand(kPointerSize)); | 493 Addu(sp, sp, Operand(kPointerSize)); |
211 } | 494 } |
212 void Pop() { | 495 void Pop(uint32_t count = 1) { |
213 Add(sp, sp, Operand(kPointerSize)); | 496 Addu(sp, sp, Operand(count * kPointerSize)); |
214 } | 497 } |
215 | 498 |
| 499 // --------------------------------------------------------------------------- |
| 500 // These functions are only used by crankshaft, so they are currently |
| 501 // unimplemented. |
| 502 |
| 503 // Push and pop the registers that can hold pointers, as defined by the |
| 504 // RegList constant kSafepointSavedRegisters. |
| 505 void PushSafepointRegisters() { |
| 506 UNIMPLEMENTED_MIPS(); |
| 507 } |
| 508 |
| 509 void PopSafepointRegisters() { |
| 510 UNIMPLEMENTED_MIPS(); |
| 511 } |
| 512 |
| 513 void PushSafepointRegistersAndDoubles() { |
| 514 UNIMPLEMENTED_MIPS(); |
| 515 } |
| 516 |
| 517 void PopSafepointRegistersAndDoubles() { |
| 518 UNIMPLEMENTED_MIPS(); |
| 519 } |
| 520 |
| 521 static int SafepointRegisterStackIndex(int reg_code) { |
| 522 UNIMPLEMENTED_MIPS(); |
| 523 return 0; |
| 524 } |
216 | 525 |
217 // --------------------------------------------------------------------------- | 526 // --------------------------------------------------------------------------- |
| 527 |
| 528 // MIPS32 R2 instruction macro. |
| 529 void Ins(Register rt, Register rs, uint16_t pos, uint16_t size); |
| 530 void Ext(Register rt, Register rs, uint16_t pos, uint16_t size); |
| 531 |
| 532 // Convert unsigned word to double. |
| 533 void Cvt_d_uw(FPURegister fd, FPURegister fs); |
| 534 void Cvt_d_uw(FPURegister fd, Register rs); |
| 535 |
| 536 // Convert double to unsigned word. |
| 537 void Trunc_uw_d(FPURegister fd, FPURegister fs); |
| 538 void Trunc_uw_d(FPURegister fd, Register rs); |
| 539 |
| 540 // Convert the HeapNumber pointed to by source to a 32bits signed integer |
| 541 // dest. If the HeapNumber does not fit into a 32bits signed integer branch |
| 542 // to not_int32 label. If FPU is available double_scratch is used but not |
| 543 // scratch2. |
| 544 void ConvertToInt32(Register source, |
| 545 Register dest, |
| 546 Register scratch, |
| 547 Register scratch2, |
| 548 FPURegister double_scratch, |
| 549 Label *not_int32); |
| 550 |
| 551 // ------------------------------------------------------------------------- |
218 // Activation frames | 552 // Activation frames |
219 | 553 |
220 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); } | 554 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); } |
221 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); } | 555 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); } |
222 | 556 |
223 // Enter specific kind of exit frame; either EXIT or | 557 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } |
224 // EXIT_DEBUG. Expects the number of arguments in register a0 and | 558 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } |
| 559 |
| 560 // Enter exit frame. |
| 561 // Expects the number of arguments in register a0 and |
225 // the builtin function to call in register a1. | 562 // the builtin function to call in register a1. |
226 // On output hold_argc, hold_function, and hold_argv are setup. | 563 // On output hold_argc, hold_function, and hold_argv are setup. |
227 void EnterExitFrame(ExitFrame::Mode mode, | 564 void EnterExitFrame(Register hold_argc, |
228 Register hold_argc, | |
229 Register hold_argv, | 565 Register hold_argv, |
230 Register hold_function); | 566 Register hold_function, |
| 567 bool save_doubles); |
231 | 568 |
232 // Leave the current exit frame. Expects the return value in v0. | 569 // Leave the current exit frame. Expects the return value in v0. |
233 void LeaveExitFrame(ExitFrame::Mode mode); | 570 void LeaveExitFrame(bool save_doubles); |
234 | 571 |
235 // Align the stack by optionally pushing a Smi zero. | 572 // Align the stack by optionally pushing a Smi zero. |
236 void AlignStack(int offset); | 573 void AlignStack(int offset); // TODO(mips) : remove this function. |
237 | 574 |
238 void SetupAlignedCall(Register scratch, int arg_count = 0); | 575 // Get the actual activation frame alignment for target environment. |
239 void ReturnFromAlignedCall(); | 576 static int ActivationFrameAlignment(); |
240 | 577 |
| 578 void LoadContext(Register dst, int context_chain_length); |
241 | 579 |
242 // --------------------------------------------------------------------------- | 580 void LoadGlobalFunction(int index, Register function); |
| 581 |
| 582 // Load the initial map from the global function. The registers |
| 583 // function and map can be the same, function is then overwritten. |
| 584 void LoadGlobalFunctionInitialMap(Register function, |
| 585 Register map, |
| 586 Register scratch); |
| 587 |
| 588 // ------------------------------------------------------------------------- |
243 // JavaScript invokes | 589 // JavaScript invokes |
244 | 590 |
245 // Invoke the JavaScript function code by either calling or jumping. | 591 // Invoke the JavaScript function code by either calling or jumping. |
246 void InvokeCode(Register code, | 592 void InvokeCode(Register code, |
247 const ParameterCount& expected, | 593 const ParameterCount& expected, |
248 const ParameterCount& actual, | 594 const ParameterCount& actual, |
249 InvokeFlag flag); | 595 InvokeFlag flag, |
| 596 PostCallGenerator* post_call_generator = NULL); |
250 | 597 |
251 void InvokeCode(Handle<Code> code, | 598 void InvokeCode(Handle<Code> code, |
252 const ParameterCount& expected, | 599 const ParameterCount& expected, |
253 const ParameterCount& actual, | 600 const ParameterCount& actual, |
254 RelocInfo::Mode rmode, | 601 RelocInfo::Mode rmode, |
255 InvokeFlag flag); | 602 InvokeFlag flag); |
256 | 603 |
257 // Invoke the JavaScript function in the given register. Changes the | 604 // Invoke the JavaScript function in the given register. Changes the |
258 // current context to the context in the function before invoking. | 605 // current context to the context in the function before invoking. |
259 void InvokeFunction(Register function, | 606 void InvokeFunction(Register function, |
260 const ParameterCount& actual, | 607 const ParameterCount& actual, |
| 608 InvokeFlag flag, |
| 609 PostCallGenerator* post_call_generator = NULL); |
| 610 |
| 611 void InvokeFunction(JSFunction* function, |
| 612 const ParameterCount& actual, |
261 InvokeFlag flag); | 613 InvokeFlag flag); |
262 | 614 |
263 | 615 |
| 616 void IsObjectJSObjectType(Register heap_object, |
| 617 Register map, |
| 618 Register scratch, |
| 619 Label* fail); |
| 620 |
| 621 void IsInstanceJSObjectType(Register map, |
| 622 Register scratch, |
| 623 Label* fail); |
| 624 |
| 625 void IsObjectJSStringType(Register object, |
| 626 Register scratch, |
| 627 Label* fail); |
| 628 |
264 #ifdef ENABLE_DEBUGGER_SUPPORT | 629 #ifdef ENABLE_DEBUGGER_SUPPORT |
265 // --------------------------------------------------------------------------- | 630 // ------------------------------------------------------------------------- |
266 // Debugger Support | 631 // Debugger Support |
267 | 632 |
268 void SaveRegistersToMemory(RegList regs); | |
269 void RestoreRegistersFromMemory(RegList regs); | |
270 void CopyRegistersFromMemoryToStack(Register base, RegList regs); | |
271 void CopyRegistersFromStackToMemory(Register base, | |
272 Register scratch, | |
273 RegList regs); | |
274 void DebugBreak(); | 633 void DebugBreak(); |
275 #endif | 634 #endif |
276 | 635 |
277 | 636 |
278 // --------------------------------------------------------------------------- | 637 // ------------------------------------------------------------------------- |
279 // Exception handling | 638 // Exception handling |
280 | 639 |
281 // Push a new try handler and link into try handler chain. | 640 // Push a new try handler and link into try handler chain. |
282 // The return address must be passed in register ra. | 641 // The return address must be passed in register ra. |
| 642 // Clobber t0, t1, t2. |
283 void PushTryHandler(CodeLocation try_location, HandlerType type); | 643 void PushTryHandler(CodeLocation try_location, HandlerType type); |
284 | 644 |
285 // Unlink the stack handler on top of the stack from the try handler chain. | 645 // Unlink the stack handler on top of the stack from the try handler chain. |
286 // Must preserve the result register. | 646 // Must preserve the result register. |
287 void PopTryHandler(); | 647 void PopTryHandler(); |
288 | 648 |
| 649 // Copies a fixed number of fields of heap objects from src to dst. |
| 650 void CopyFields(Register dst, Register src, RegList temps, int field_count); |
289 | 651 |
290 // --------------------------------------------------------------------------- | 652 // ------------------------------------------------------------------------- |
291 // Support functions. | 653 // Support functions. |
292 | 654 |
| 655 // Try to get function prototype of a function and puts the value in |
| 656 // the result register. Checks that the function really is a |
| 657 // function and jumps to the miss label if the fast checks fail. The |
| 658 // function register will be untouched; the other registers may be |
| 659 // clobbered. |
| 660 void TryGetFunctionPrototype(Register function, |
| 661 Register result, |
| 662 Register scratch, |
| 663 Label* miss); |
| 664 |
293 void GetObjectType(Register function, | 665 void GetObjectType(Register function, |
294 Register map, | 666 Register map, |
295 Register type_reg); | 667 Register type_reg); |
296 | 668 |
297 inline void BranchOnSmi(Register value, Label* smi_label, | 669 // Check if the map of an object is equal to a specified map (either |
298 Register scratch = at) { | 670 // given directly or as an index into the root list) and branch to |
299 ASSERT_EQ(0, kSmiTag); | 671 // label if not. Skip the smi check if not required (object is known |
300 andi(scratch, value, kSmiTagMask); | 672 // to be a heap object) |
301 Branch(eq, smi_label, scratch, Operand(zero_reg)); | 673 void CheckMap(Register obj, |
302 } | 674 Register scratch, |
| 675 Handle<Map> map, |
| 676 Label* fail, |
| 677 bool is_heap_object); |
303 | 678 |
304 | 679 void CheckMap(Register obj, |
305 inline void BranchOnNotSmi(Register value, Label* not_smi_label, | 680 Register scratch, |
306 Register scratch = at) { | 681 Heap::RootListIndex index, |
307 ASSERT_EQ(0, kSmiTag); | 682 Label* fail, |
308 andi(scratch, value, kSmiTagMask); | 683 bool is_heap_object); |
309 Branch(ne, not_smi_label, scratch, Operand(zero_reg)); | |
310 } | |
311 | |
312 void CallBuiltin(ExternalReference builtin_entry); | |
313 void CallBuiltin(Register target); | |
314 void JumpToBuiltin(ExternalReference builtin_entry); | |
315 void JumpToBuiltin(Register target); | |
316 | 684 |
317 // Generates code for reporting that an illegal operation has | 685 // Generates code for reporting that an illegal operation has |
318 // occurred. | 686 // occurred. |
319 void IllegalOperation(int num_arguments); | 687 void IllegalOperation(int num_arguments); |
320 | 688 |
| 689 // Picks out an array index from the hash field. |
| 690 // Register use: |
| 691 // hash - holds the index's hash. Clobbered. |
| 692 // index - holds the overwritten index on exit. |
| 693 void IndexFromHash(Register hash, Register index); |
321 | 694 |
322 // --------------------------------------------------------------------------- | 695 // Load the value of a number object into a FPU double register. If the |
| 696 // object is not a number a jump to the label not_number is performed |
| 697 // and the FPU double register is unchanged. |
| 698 void ObjectToDoubleFPURegister( |
| 699 Register object, |
| 700 FPURegister value, |
| 701 Register scratch1, |
| 702 Register scratch2, |
| 703 Register heap_number_map, |
| 704 Label* not_number, |
| 705 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS); |
| 706 |
| 707 // Load the value of a smi object into a FPU double register. The register |
| 708 // scratch1 can be the same register as smi in which case smi will hold the |
| 709 // untagged value afterwards. |
| 710 void SmiToDoubleFPURegister(Register smi, |
| 711 FPURegister value, |
| 712 Register scratch1); |
| 713 |
| 714 // ------------------------------------------------------------------------- |
323 // Runtime calls | 715 // Runtime calls |
324 | 716 |
325 // Call a code stub. | 717 // Call a code stub. |
326 void CallStub(CodeStub* stub, Condition cond = cc_always, | 718 void CallStub(CodeStub* stub, Condition cond = cc_always, |
327 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 719 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); |
| 720 |
| 721 // Tail call a code stub (jump). |
| 722 void TailCallStub(CodeStub* stub); |
| 723 |
328 void CallJSExitStub(CodeStub* stub); | 724 void CallJSExitStub(CodeStub* stub); |
329 | 725 |
330 // Return from a code stub after popping its arguments. | |
331 void StubReturn(int argc); | |
332 | |
333 // Call a runtime routine. | 726 // Call a runtime routine. |
334 void CallRuntime(Runtime::Function* f, int num_arguments); | 727 void CallRuntime(const Runtime::Function* f, int num_arguments); |
| 728 void CallRuntimeSaveDoubles(Runtime::FunctionId id); |
335 | 729 |
336 // Convenience function: Same as above, but takes the fid instead. | 730 // Convenience function: Same as above, but takes the fid instead. |
337 void CallRuntime(Runtime::FunctionId fid, int num_arguments); | 731 void CallRuntime(Runtime::FunctionId fid, int num_arguments); |
338 | 732 |
| 733 // Convenience function: call an external reference. |
| 734 void CallExternalReference(const ExternalReference& ext, |
| 735 int num_arguments); |
| 736 |
339 // Tail call of a runtime routine (jump). | 737 // Tail call of a runtime routine (jump). |
340 // Like JumpToExternalReference, but also takes care of passing the number | 738 // Like JumpToExternalReference, but also takes care of passing the number |
341 // of parameters. | 739 // of parameters. |
342 void TailCallExternalReference(const ExternalReference& ext, | 740 void TailCallExternalReference(const ExternalReference& ext, |
343 int num_arguments, | 741 int num_arguments, |
344 int result_size); | 742 int result_size); |
345 | 743 |
346 // Convenience function: tail call a runtime routine (jump). | 744 // Convenience function: tail call a runtime routine (jump). |
347 void TailCallRuntime(Runtime::FunctionId fid, | 745 void TailCallRuntime(Runtime::FunctionId fid, |
348 int num_arguments, | 746 int num_arguments, |
349 int result_size); | 747 int result_size); |
350 | 748 |
| 749 // Before calling a C-function from generated code, align arguments on stack |
| 750 // and add space for the four mips argument slots. |
| 751 // After aligning the frame, non-register arguments must be stored on the |
| 752 // stack, after the argument-slots using helper: CFunctionArgumentOperand(). |
| 753 // The argument count assumes all arguments are word sized. |
| 754 // Some compilers/platforms require the stack to be aligned when calling |
| 755 // C++ code. |
| 756 // Needs a scratch register to do some arithmetic. This register will be |
| 757 // trashed. |
| 758 void PrepareCallCFunction(int num_arguments, Register scratch); |
| 759 |
| 760 // Arguments 1-4 are placed in registers a0 thru a3 respectively. |
| 761 // Arguments 5..n are stored to stack using following: |
| 762 // sw(t0, CFunctionArgumentOperand(5)); |
| 763 |
| 764 // Calls a C function and cleans up the space for arguments allocated |
| 765 // by PrepareCallCFunction. The called function is not allowed to trigger a |
| 766 // garbage collection, since that might move the code and invalidate the |
| 767 // return address (unless this is somehow accounted for by the called |
| 768 // function). |
| 769 void CallCFunction(ExternalReference function, int num_arguments); |
| 770 void CallCFunction(Register function, Register scratch, int num_arguments); |
| 771 |
351 // Jump to the builtin routine. | 772 // Jump to the builtin routine. |
352 void JumpToExternalReference(const ExternalReference& builtin); | 773 void JumpToExternalReference(const ExternalReference& builtin); |
353 | 774 |
354 // Invoke specified builtin JavaScript function. Adds an entry to | 775 // Invoke specified builtin JavaScript function. Adds an entry to |
355 // the unresolved list if the name does not resolve. | 776 // the unresolved list if the name does not resolve. |
356 void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags); | 777 void InvokeBuiltin(Builtins::JavaScript id, |
| 778 InvokeJSFlags flags, |
| 779 PostCallGenerator* post_call_generator = NULL); |
357 | 780 |
358 // Store the code object for the given builtin in the target register and | 781 // Store the code object for the given builtin in the target register and |
359 // setup the function in r1. | 782 // setup the function in a1. |
360 void GetBuiltinEntry(Register target, Builtins::JavaScript id); | 783 void GetBuiltinEntry(Register target, Builtins::JavaScript id); |
361 | 784 |
| 785 // Store the function for the given builtin in the target register. |
| 786 void GetBuiltinFunction(Register target, Builtins::JavaScript id); |
| 787 |
362 struct Unresolved { | 788 struct Unresolved { |
363 int pc; | 789 int pc; |
364 uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders. | 790 uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders. |
365 const char* name; | 791 const char* name; |
366 }; | 792 }; |
367 List<Unresolved>* unresolved() { return &unresolved_; } | |
368 | 793 |
369 Handle<Object> CodeObject() { return code_object_; } | 794 Handle<Object> CodeObject() { return code_object_; } |
370 | 795 |
371 | 796 // ------------------------------------------------------------------------- |
372 // --------------------------------------------------------------------------- | |
373 // Stack limit support | |
374 | |
375 void StackLimitCheck(Label* on_stack_limit_hit); | |
376 | |
377 | |
378 // --------------------------------------------------------------------------- | |
379 // StatsCounter support | 797 // StatsCounter support |
380 | 798 |
381 void SetCounter(StatsCounter* counter, int value, | 799 void SetCounter(StatsCounter* counter, int value, |
382 Register scratch1, Register scratch2); | 800 Register scratch1, Register scratch2); |
383 void IncrementCounter(StatsCounter* counter, int value, | 801 void IncrementCounter(StatsCounter* counter, int value, |
384 Register scratch1, Register scratch2); | 802 Register scratch1, Register scratch2); |
385 void DecrementCounter(StatsCounter* counter, int value, | 803 void DecrementCounter(StatsCounter* counter, int value, |
386 Register scratch1, Register scratch2); | 804 Register scratch1, Register scratch2); |
387 | 805 |
388 | 806 |
389 // --------------------------------------------------------------------------- | 807 // ------------------------------------------------------------------------- |
390 // Debugging | 808 // Debugging |
391 | 809 |
392 // Calls Abort(msg) if the condition cc is not satisfied. | 810 // Calls Abort(msg) if the condition cc is not satisfied. |
393 // Use --debug_code to enable. | 811 // Use --debug_code to enable. |
394 void Assert(Condition cc, const char* msg, Register rs, Operand rt); | 812 void Assert(Condition cc, const char* msg, Register rs, Operand rt); |
| 813 void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index); |
| 814 void AssertFastElements(Register elements); |
395 | 815 |
396 // Like Assert(), but always enabled. | 816 // Like Assert(), but always enabled. |
397 void Check(Condition cc, const char* msg, Register rs, Operand rt); | 817 void Check(Condition cc, const char* msg, Register rs, Operand rt); |
398 | 818 |
399 // Print a message to stdout and abort execution. | 819 // Print a message to stdout and abort execution. |
400 void Abort(const char* msg); | 820 void Abort(const char* msg); |
401 | 821 |
402 // Verify restrictions about code generated in stubs. | 822 // Verify restrictions about code generated in stubs. |
403 void set_generating_stub(bool value) { generating_stub_ = value; } | 823 void set_generating_stub(bool value) { generating_stub_ = value; } |
404 bool generating_stub() { return generating_stub_; } | 824 bool generating_stub() { return generating_stub_; } |
405 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } | 825 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } |
406 bool allow_stub_calls() { return allow_stub_calls_; } | 826 bool allow_stub_calls() { return allow_stub_calls_; } |
407 | 827 |
| 828 // --------------------------------------------------------------------------- |
| 829 // Number utilities |
| 830 |
| 831 // Check whether the value of reg is a power of two and not zero. If not |
| 832 // control continues at the label not_power_of_two. If reg is a power of two |
| 833 // the register scratch contains the value of (reg - 1) when control falls |
| 834 // through. |
| 835 void JumpIfNotPowerOfTwoOrZero(Register reg, |
| 836 Register scratch, |
| 837 Label* not_power_of_two_or_zero); |
| 838 |
| 839 // ------------------------------------------------------------------------- |
| 840 // Smi utilities |
| 841 |
| 842 // Try to convert int32 to smi. If the value is to large, preserve |
| 843 // the original value and jump to not_a_smi. Destroys scratch and |
| 844 // sets flags. |
| 845 // This is only used by crankshaft atm so it is unimplemented on MIPS. |
| 846 void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) { |
| 847 UNIMPLEMENTED_MIPS(); |
| 848 } |
| 849 |
| 850 void SmiTag(Register reg) { |
| 851 Addu(reg, reg, reg); |
| 852 } |
| 853 |
| 854 void SmiTag(Register dst, Register src) { |
| 855 Addu(dst, src, src); |
| 856 } |
| 857 |
| 858 void SmiUntag(Register reg) { |
| 859 sra(reg, reg, kSmiTagSize); |
| 860 } |
| 861 |
| 862 void SmiUntag(Register dst, Register src) { |
| 863 sra(dst, src, kSmiTagSize); |
| 864 } |
| 865 |
| 866 // Jump the register contains a smi. |
| 867 inline void JumpIfSmi(Register value, Label* smi_label, |
| 868 Register scratch = at) { |
| 869 ASSERT_EQ(0, kSmiTag); |
| 870 andi(scratch, value, kSmiTagMask); |
| 871 Branch(smi_label, eq, scratch, Operand(zero_reg)); |
| 872 } |
| 873 |
| 874 // Jump if the register contains a non-smi. |
| 875 inline void JumpIfNotSmi(Register value, Label* not_smi_label, |
| 876 Register scratch = at) { |
| 877 ASSERT_EQ(0, kSmiTag); |
| 878 andi(scratch, value, kSmiTagMask); |
| 879 Branch(not_smi_label, ne, scratch, Operand(zero_reg)); |
| 880 } |
| 881 |
| 882 // Jump if either of the registers contain a non-smi. |
| 883 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); |
| 884 // Jump if either of the registers contain a smi. |
| 885 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); |
| 886 |
| 887 // Abort execution if argument is a smi. Used in debug code. |
| 888 void AbortIfSmi(Register object); |
| 889 void AbortIfNotSmi(Register object); |
| 890 |
| 891 // Abort execution if argument is not the root value with the given index. |
| 892 void AbortIfNotRootValue(Register src, |
| 893 Heap::RootListIndex root_value_index, |
| 894 const char* message); |
| 895 |
| 896 // --------------------------------------------------------------------------- |
| 897 // HeapNumber utilities |
| 898 |
| 899 void JumpIfNotHeapNumber(Register object, |
| 900 Register heap_number_map, |
| 901 Register scratch, |
| 902 Label* on_not_heap_number); |
| 903 |
| 904 // ------------------------------------------------------------------------- |
| 905 // String utilities |
| 906 |
| 907 // Checks if both instance types are sequential ASCII strings and jumps to |
| 908 // label if either is not. |
| 909 void JumpIfBothInstanceTypesAreNotSequentialAscii( |
| 910 Register first_object_instance_type, |
| 911 Register second_object_instance_type, |
| 912 Register scratch1, |
| 913 Register scratch2, |
| 914 Label* failure); |
| 915 |
| 916 // Check if instance type is sequential ASCII string and jump to label if |
| 917 // it is not. |
| 918 void JumpIfInstanceTypeIsNotSequentialAscii(Register type, |
| 919 Register scratch, |
| 920 Label* failure); |
| 921 |
| 922 // Test that both first and second are sequential ASCII strings. |
| 923 // Assume that they are non-smis. |
| 924 void JumpIfNonSmisNotBothSequentialAsciiStrings(Register first, |
| 925 Register second, |
| 926 Register scratch1, |
| 927 Register scratch2, |
| 928 Label* failure); |
| 929 |
| 930 // Test that both first and second are sequential ASCII strings. |
| 931 // Check that they are non-smis. |
| 932 void JumpIfNotBothSequentialAsciiStrings(Register first, |
| 933 Register second, |
| 934 Register scratch1, |
| 935 Register scratch2, |
| 936 Label* failure); |
| 937 |
408 private: | 938 private: |
409 List<Unresolved> unresolved_; | 939 void CallCFunctionHelper(Register function, |
410 bool generating_stub_; | 940 ExternalReference function_reference, |
411 bool allow_stub_calls_; | 941 Register scratch, |
412 // This handle will be patched with the code object on installation. | 942 int num_arguments); |
413 Handle<Object> code_object_; | |
414 | 943 |
| 944 void Jump(intptr_t target, RelocInfo::Mode rmode, |
| 945 BranchDelaySlot bd = PROTECT); |
415 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = cc_always, | 946 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = cc_always, |
416 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 947 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg), |
| 948 BranchDelaySlot bd = PROTECT); |
| 949 void Call(intptr_t target, RelocInfo::Mode rmode, |
| 950 BranchDelaySlot bd = PROTECT); |
417 void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = cc_always, | 951 void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = cc_always, |
418 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg)); | 952 Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg), |
| 953 BranchDelaySlot bd = PROTECT); |
419 | 954 |
420 // Helper functions for generating invokes. | 955 // Helper functions for generating invokes. |
421 void InvokePrologue(const ParameterCount& expected, | 956 void InvokePrologue(const ParameterCount& expected, |
422 const ParameterCount& actual, | 957 const ParameterCount& actual, |
423 Handle<Code> code_constant, | 958 Handle<Code> code_constant, |
424 Register code_reg, | 959 Register code_reg, |
425 Label* done, | 960 Label* done, |
426 InvokeFlag flag); | 961 InvokeFlag flag, |
| 962 PostCallGenerator* post_call_generator = NULL); |
427 | 963 |
428 // Get the code for the given builtin. Returns if able to resolve | 964 // Get the code for the given builtin. Returns if able to resolve |
429 // the function in the 'resolved' flag. | 965 // the function in the 'resolved' flag. |
430 Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved); | 966 Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved); |
431 | 967 |
432 // Activation support. | 968 // Activation support. |
433 // EnterFrame clobbers t0 and t1. | |
434 void EnterFrame(StackFrame::Type type); | 969 void EnterFrame(StackFrame::Type type); |
435 void LeaveFrame(StackFrame::Type type); | 970 void LeaveFrame(StackFrame::Type type); |
| 971 |
| 972 void InitializeNewString(Register string, |
| 973 Register length, |
| 974 Heap::RootListIndex map_index, |
| 975 Register scratch1, |
| 976 Register scratch2); |
| 977 |
| 978 |
| 979 bool generating_stub_; |
| 980 bool allow_stub_calls_; |
| 981 // This handle will be patched with the code object on installation. |
| 982 Handle<Object> code_object_; |
| 983 }; |
| 984 |
| 985 |
| 986 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 987 // The code patcher is used to patch (typically) small parts of code e.g. for |
| 988 // debugging and other types of instrumentation. When using the code patcher |
| 989 // the exact number of bytes specified must be emitted. It is not legal to emit |
| 990 // relocation information. If any of these constraints are violated it causes |
| 991 // an assertion to fail. |
| 992 class CodePatcher { |
| 993 public: |
| 994 CodePatcher(byte* address, int instructions); |
| 995 virtual ~CodePatcher(); |
| 996 |
| 997 // Macro assembler to emit code. |
| 998 MacroAssembler* masm() { return &masm_; } |
| 999 |
| 1000 // Emit an instruction directly. |
| 1001 void Emit(Instr x); |
| 1002 |
| 1003 // Emit an address directly. |
| 1004 void Emit(Address addr); |
| 1005 |
| 1006 private: |
| 1007 byte* address_; // The address of the code being patched. |
| 1008 int instructions_; // Number of instructions of the expected patch size. |
| 1009 int size_; // Number of bytes of the expected patch size. |
| 1010 MacroAssembler masm_; // Macro assembler used to generate the code. |
| 1011 }; |
| 1012 #endif // ENABLE_DEBUGGER_SUPPORT |
| 1013 |
| 1014 |
| 1015 // Helper class for generating code or data associated with the code |
| 1016 // right after a call instruction. As an example this can be used to |
| 1017 // generate safepoint data after calls for crankshaft. |
| 1018 class PostCallGenerator { |
| 1019 public: |
| 1020 PostCallGenerator() { } |
| 1021 virtual ~PostCallGenerator() { } |
| 1022 virtual void Generate() = 0; |
436 }; | 1023 }; |
437 | 1024 |
438 | 1025 |
439 // ----------------------------------------------------------------------------- | 1026 // ----------------------------------------------------------------------------- |
440 // Static helper functions. | 1027 // Static helper functions. |
441 | 1028 |
| 1029 static MemOperand ContextOperand(Register context, int index) { |
| 1030 return MemOperand(context, Context::SlotOffset(index)); |
| 1031 } |
| 1032 |
| 1033 |
| 1034 static inline MemOperand GlobalObjectOperand() { |
| 1035 return ContextOperand(cp, Context::GLOBAL_INDEX); |
| 1036 } |
| 1037 |
| 1038 |
442 // Generate a MemOperand for loading a field from an object. | 1039 // Generate a MemOperand for loading a field from an object. |
443 static inline MemOperand FieldMemOperand(Register object, int offset) { | 1040 static inline MemOperand FieldMemOperand(Register object, int offset) { |
444 return MemOperand(object, offset - kHeapObjectTag); | 1041 return MemOperand(object, offset - kHeapObjectTag); |
445 } | 1042 } |
446 | 1043 |
447 | 1044 |
448 | 1045 |
449 #ifdef GENERATED_CODE_COVERAGE | 1046 #ifdef GENERATED_CODE_COVERAGE |
450 #define CODE_COVERAGE_STRINGIFY(x) #x | 1047 #define CODE_COVERAGE_STRINGIFY(x) #x |
451 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) | 1048 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) |
452 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) | 1049 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) |
453 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> | 1050 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> |
454 #else | 1051 #else |
455 #define ACCESS_MASM(masm) masm-> | 1052 #define ACCESS_MASM(masm) masm-> |
456 #endif | 1053 #endif |
457 | 1054 |
458 } } // namespace v8::internal | 1055 } } // namespace v8::internal |
459 | 1056 |
460 #endif // V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ | 1057 #endif // V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ |
461 | 1058 |
OLD | NEW |