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