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