| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 int MacroAssembler::CallSize(Register target, Condition cond) { | 106 int MacroAssembler::CallSize(Register target, Condition cond) { |
| 107 #if USE_BLX | 107 #if USE_BLX |
| 108 return kInstrSize; | 108 return kInstrSize; |
| 109 #else | 109 #else |
| 110 return 2 * kInstrSize; | 110 return 2 * kInstrSize; |
| 111 #endif | 111 #endif |
| 112 } | 112 } |
| 113 | 113 |
| 114 | 114 |
| 115 void MacroAssembler::Call(Register target, Condition cond) { | 115 void MacroAssembler::Call(Register target, Condition cond) { |
| 116 // Block constant pool for the call instruction sequence. |
| 117 BlockConstPoolScope block_const_pool(this); |
| 116 #ifdef DEBUG | 118 #ifdef DEBUG |
| 117 int pre_position = pc_offset(); | 119 int pre_position = pc_offset(); |
| 118 #endif | 120 #endif |
| 119 | 121 |
| 120 #if USE_BLX | 122 #if USE_BLX |
| 121 blx(target, cond); | 123 blx(target, cond); |
| 122 #else | 124 #else |
| 123 // set lr for return at current pc + 8 | 125 // set lr for return at current pc + 8 |
| 124 { BlockConstPoolScope block_const_pool(this); | 126 mov(lr, Operand(pc), LeaveCC, cond); |
| 125 mov(lr, Operand(pc), LeaveCC, cond); | 127 mov(pc, Operand(target), LeaveCC, cond); |
| 126 mov(pc, Operand(target), LeaveCC, cond); | |
| 127 } | |
| 128 #endif | 128 #endif |
| 129 | 129 |
| 130 #ifdef DEBUG | 130 #ifdef DEBUG |
| 131 int post_position = pc_offset(); | 131 int post_position = pc_offset(); |
| 132 CHECK_EQ(pre_position + CallSize(target, cond), post_position); | 132 CHECK_EQ(pre_position + CallSize(target, cond), post_position); |
| 133 #endif | 133 #endif |
| 134 } | 134 } |
| 135 | 135 |
| 136 | 136 |
| 137 int MacroAssembler::CallSize( | 137 int MacroAssembler::CallSize( |
| 138 intptr_t target, RelocInfo::Mode rmode, Condition cond) { | 138 intptr_t target, RelocInfo::Mode rmode, Condition cond) { |
| 139 int size = 2 * kInstrSize; | 139 int size = 2 * kInstrSize; |
| 140 Instr mov_instr = cond | MOV | LeaveCC; | 140 Instr mov_instr = cond | MOV | LeaveCC; |
| 141 if (!Operand(target, rmode).is_single_instruction(mov_instr)) { | 141 if (!Operand(target, rmode).is_single_instruction(mov_instr)) { |
| 142 size += kInstrSize; | 142 size += kInstrSize; |
| 143 } | 143 } |
| 144 return size; | 144 return size; |
| 145 } | 145 } |
| 146 | 146 |
| 147 | 147 |
| 148 void MacroAssembler::Call( | 148 void MacroAssembler::Call( |
| 149 intptr_t target, RelocInfo::Mode rmode, Condition cond) { | 149 intptr_t target, RelocInfo::Mode rmode, Condition cond) { |
| 150 // Block constant pool for the call instruction sequence. |
| 151 BlockConstPoolScope block_const_pool(this); |
| 150 #ifdef DEBUG | 152 #ifdef DEBUG |
| 151 int pre_position = pc_offset(); | 153 int pre_position = pc_offset(); |
| 152 #endif | 154 #endif |
| 153 | 155 |
| 154 #if USE_BLX | 156 #if USE_BLX |
| 155 // On ARMv5 and after the recommended call sequence is: | 157 // On ARMv5 and after the recommended call sequence is: |
| 156 // ldr ip, [pc, #...] | 158 // ldr ip, [pc, #...] |
| 157 // blx ip | 159 // blx ip |
| 158 | 160 |
| 159 // The two instructions (ldr and blx) could be separated by a constant | 161 // Statement positions are expected to be recorded when the target |
| 160 // pool and the code would still work. The issue comes from the | 162 // address is loaded. The mov method will automatically record |
| 161 // patching code which expect the ldr to be just above the blx. | 163 // positions when pc is the target, since this is not the case here |
| 162 { BlockConstPoolScope block_const_pool(this); | 164 // we have to do it explicitly. |
| 163 // Statement positions are expected to be recorded when the target | 165 positions_recorder()->WriteRecordedPositions(); |
| 164 // address is loaded. The mov method will automatically record | |
| 165 // positions when pc is the target, since this is not the case here | |
| 166 // we have to do it explicitly. | |
| 167 positions_recorder()->WriteRecordedPositions(); | |
| 168 | 166 |
| 169 mov(ip, Operand(target, rmode), LeaveCC, cond); | 167 mov(ip, Operand(target, rmode), LeaveCC, cond); |
| 170 blx(ip, cond); | 168 blx(ip, cond); |
| 171 } | |
| 172 | 169 |
| 173 ASSERT(kCallTargetAddressOffset == 2 * kInstrSize); | 170 ASSERT(kCallTargetAddressOffset == 2 * kInstrSize); |
| 174 #else | 171 #else |
| 175 { BlockConstPoolScope block_const_pool(this); | 172 // Set lr for return at current pc + 8. |
| 176 // Set lr for return at current pc + 8. | 173 mov(lr, Operand(pc), LeaveCC, cond); |
| 177 mov(lr, Operand(pc), LeaveCC, cond); | 174 // Emit a ldr<cond> pc, [pc + offset of target in constant pool]. |
| 178 // Emit a ldr<cond> pc, [pc + offset of target in constant pool]. | 175 mov(pc, Operand(target, rmode), LeaveCC, cond); |
| 179 mov(pc, Operand(target, rmode), LeaveCC, cond); | |
| 180 } | |
| 181 ASSERT(kCallTargetAddressOffset == kInstrSize); | 176 ASSERT(kCallTargetAddressOffset == kInstrSize); |
| 182 #endif | 177 #endif |
| 183 | 178 |
| 184 #ifdef DEBUG | 179 #ifdef DEBUG |
| 185 int post_position = pc_offset(); | 180 int post_position = pc_offset(); |
| 186 CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position); | 181 CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position); |
| 187 #endif | 182 #endif |
| 188 } | 183 } |
| 189 | 184 |
| 190 | 185 |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 void MacroAssembler::StoreRoot(Register source, | 426 void MacroAssembler::StoreRoot(Register source, |
| 432 Heap::RootListIndex index, | 427 Heap::RootListIndex index, |
| 433 Condition cond) { | 428 Condition cond) { |
| 434 str(source, MemOperand(roots, index << kPointerSizeLog2), cond); | 429 str(source, MemOperand(roots, index << kPointerSizeLog2), cond); |
| 435 } | 430 } |
| 436 | 431 |
| 437 | 432 |
| 438 void MacroAssembler::RecordWriteHelper(Register object, | 433 void MacroAssembler::RecordWriteHelper(Register object, |
| 439 Register address, | 434 Register address, |
| 440 Register scratch) { | 435 Register scratch) { |
| 441 if (FLAG_debug_code) { | 436 if (emit_debug_code()) { |
| 442 // Check that the object is not in new space. | 437 // Check that the object is not in new space. |
| 443 Label not_in_new_space; | 438 Label not_in_new_space; |
| 444 InNewSpace(object, scratch, ne, ¬_in_new_space); | 439 InNewSpace(object, scratch, ne, ¬_in_new_space); |
| 445 Abort("new-space object passed to RecordWriteHelper"); | 440 Abort("new-space object passed to RecordWriteHelper"); |
| 446 bind(¬_in_new_space); | 441 bind(¬_in_new_space); |
| 447 } | 442 } |
| 448 | 443 |
| 449 // Calculate page address. | 444 // Calculate page address. |
| 450 Bfc(object, 0, kPageSizeBits); | 445 Bfc(object, 0, kPageSizeBits); |
| 451 | 446 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 // Add offset into the object. | 488 // Add offset into the object. |
| 494 add(scratch0, object, offset); | 489 add(scratch0, object, offset); |
| 495 | 490 |
| 496 // Record the actual write. | 491 // Record the actual write. |
| 497 RecordWriteHelper(object, scratch0, scratch1); | 492 RecordWriteHelper(object, scratch0, scratch1); |
| 498 | 493 |
| 499 bind(&done); | 494 bind(&done); |
| 500 | 495 |
| 501 // Clobber all input registers when running with the debug-code flag | 496 // Clobber all input registers when running with the debug-code flag |
| 502 // turned on to provoke errors. | 497 // turned on to provoke errors. |
| 503 if (FLAG_debug_code) { | 498 if (emit_debug_code()) { |
| 504 mov(object, Operand(BitCast<int32_t>(kZapValue))); | 499 mov(object, Operand(BitCast<int32_t>(kZapValue))); |
| 505 mov(scratch0, Operand(BitCast<int32_t>(kZapValue))); | 500 mov(scratch0, Operand(BitCast<int32_t>(kZapValue))); |
| 506 mov(scratch1, Operand(BitCast<int32_t>(kZapValue))); | 501 mov(scratch1, Operand(BitCast<int32_t>(kZapValue))); |
| 507 } | 502 } |
| 508 } | 503 } |
| 509 | 504 |
| 510 | 505 |
| 511 // Will clobber 4 registers: object, address, scratch, ip. The | 506 // Will clobber 4 registers: object, address, scratch, ip. The |
| 512 // register 'object' contains a heap object pointer. The heap object | 507 // register 'object' contains a heap object pointer. The heap object |
| 513 // tag is shifted away. | 508 // tag is shifted away. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 525 // region marks for new space pages. | 520 // region marks for new space pages. |
| 526 InNewSpace(object, scratch, eq, &done); | 521 InNewSpace(object, scratch, eq, &done); |
| 527 | 522 |
| 528 // Record the actual write. | 523 // Record the actual write. |
| 529 RecordWriteHelper(object, address, scratch); | 524 RecordWriteHelper(object, address, scratch); |
| 530 | 525 |
| 531 bind(&done); | 526 bind(&done); |
| 532 | 527 |
| 533 // Clobber all input registers when running with the debug-code flag | 528 // Clobber all input registers when running with the debug-code flag |
| 534 // turned on to provoke errors. | 529 // turned on to provoke errors. |
| 535 if (FLAG_debug_code) { | 530 if (emit_debug_code()) { |
| 536 mov(object, Operand(BitCast<int32_t>(kZapValue))); | 531 mov(object, Operand(BitCast<int32_t>(kZapValue))); |
| 537 mov(address, Operand(BitCast<int32_t>(kZapValue))); | 532 mov(address, Operand(BitCast<int32_t>(kZapValue))); |
| 538 mov(scratch, Operand(BitCast<int32_t>(kZapValue))); | 533 mov(scratch, Operand(BitCast<int32_t>(kZapValue))); |
| 539 } | 534 } |
| 540 } | 535 } |
| 541 | 536 |
| 542 | 537 |
| 543 // Push and pop all registers that can hold pointers. | 538 // Push and pop all registers that can hold pointers. |
| 544 void MacroAssembler::PushSafepointRegisters() { | 539 void MacroAssembler::PushSafepointRegisters() { |
| 545 // Safepoints expect a block of contiguous register values starting with r0: | 540 // Safepoints expect a block of contiguous register values starting with r0: |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 | 724 |
| 730 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { | 725 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { |
| 731 // Setup the frame structure on the stack. | 726 // Setup the frame structure on the stack. |
| 732 ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); | 727 ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); |
| 733 ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); | 728 ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); |
| 734 ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); | 729 ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); |
| 735 Push(lr, fp); | 730 Push(lr, fp); |
| 736 mov(fp, Operand(sp)); // Setup new frame pointer. | 731 mov(fp, Operand(sp)); // Setup new frame pointer. |
| 737 // Reserve room for saved entry sp and code object. | 732 // Reserve room for saved entry sp and code object. |
| 738 sub(sp, sp, Operand(2 * kPointerSize)); | 733 sub(sp, sp, Operand(2 * kPointerSize)); |
| 739 if (FLAG_debug_code) { | 734 if (emit_debug_code()) { |
| 740 mov(ip, Operand(0)); | 735 mov(ip, Operand(0)); |
| 741 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 736 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
| 742 } | 737 } |
| 743 mov(ip, Operand(CodeObject())); | 738 mov(ip, Operand(CodeObject())); |
| 744 str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); | 739 str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); |
| 745 | 740 |
| 746 // Save the frame pointer and the context in top. | 741 // Save the frame pointer and the context in top. |
| 747 mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address))); | 742 mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address))); |
| 748 str(fp, MemOperand(ip)); | 743 str(fp, MemOperand(ip)); |
| 749 mov(ip, Operand(ExternalReference(Isolate::k_context_address))); | 744 mov(ip, Operand(ExternalReference(Isolate::k_context_address))); |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1136 | 1131 |
| 1137 // Before returning we restore the context from the frame pointer if | 1132 // Before returning we restore the context from the frame pointer if |
| 1138 // not NULL. The frame pointer is NULL in the exception handler of a | 1133 // not NULL. The frame pointer is NULL in the exception handler of a |
| 1139 // JS entry frame. | 1134 // JS entry frame. |
| 1140 cmp(fp, Operand(0, RelocInfo::NONE)); | 1135 cmp(fp, Operand(0, RelocInfo::NONE)); |
| 1141 // Set cp to NULL if fp is NULL. | 1136 // Set cp to NULL if fp is NULL. |
| 1142 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); | 1137 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
| 1143 // Restore cp otherwise. | 1138 // Restore cp otherwise. |
| 1144 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); | 1139 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
| 1145 #ifdef DEBUG | 1140 #ifdef DEBUG |
| 1146 if (FLAG_debug_code) { | 1141 if (emit_debug_code()) { |
| 1147 mov(lr, Operand(pc)); | 1142 mov(lr, Operand(pc)); |
| 1148 } | 1143 } |
| 1149 #endif | 1144 #endif |
| 1150 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 1145 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
| 1151 pop(pc); | 1146 pop(pc); |
| 1152 } | 1147 } |
| 1153 | 1148 |
| 1154 | 1149 |
| 1155 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, | 1150 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, |
| 1156 Register value) { | 1151 Register value) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1210 ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. | 1205 ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. |
| 1211 // Before returning we restore the context from the frame pointer if | 1206 // Before returning we restore the context from the frame pointer if |
| 1212 // not NULL. The frame pointer is NULL in the exception handler of a | 1207 // not NULL. The frame pointer is NULL in the exception handler of a |
| 1213 // JS entry frame. | 1208 // JS entry frame. |
| 1214 cmp(fp, Operand(0, RelocInfo::NONE)); | 1209 cmp(fp, Operand(0, RelocInfo::NONE)); |
| 1215 // Set cp to NULL if fp is NULL. | 1210 // Set cp to NULL if fp is NULL. |
| 1216 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); | 1211 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
| 1217 // Restore cp otherwise. | 1212 // Restore cp otherwise. |
| 1218 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); | 1213 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
| 1219 #ifdef DEBUG | 1214 #ifdef DEBUG |
| 1220 if (FLAG_debug_code) { | 1215 if (emit_debug_code()) { |
| 1221 mov(lr, Operand(pc)); | 1216 mov(lr, Operand(pc)); |
| 1222 } | 1217 } |
| 1223 #endif | 1218 #endif |
| 1224 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 1219 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
| 1225 pop(pc); | 1220 pop(pc); |
| 1226 } | 1221 } |
| 1227 | 1222 |
| 1228 | 1223 |
| 1229 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, | 1224 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
| 1230 Register scratch, | 1225 Register scratch, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1242 cmp(scratch, Operand(0, RelocInfo::NONE)); | 1237 cmp(scratch, Operand(0, RelocInfo::NONE)); |
| 1243 Check(ne, "we should not have an empty lexical context"); | 1238 Check(ne, "we should not have an empty lexical context"); |
| 1244 #endif | 1239 #endif |
| 1245 | 1240 |
| 1246 // Load the global context of the current context. | 1241 // Load the global context of the current context. |
| 1247 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 1242 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
| 1248 ldr(scratch, FieldMemOperand(scratch, offset)); | 1243 ldr(scratch, FieldMemOperand(scratch, offset)); |
| 1249 ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset)); | 1244 ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset)); |
| 1250 | 1245 |
| 1251 // Check the context is a global context. | 1246 // Check the context is a global context. |
| 1252 if (FLAG_debug_code) { | 1247 if (emit_debug_code()) { |
| 1253 // TODO(119): avoid push(holder_reg)/pop(holder_reg) | 1248 // TODO(119): avoid push(holder_reg)/pop(holder_reg) |
| 1254 // Cannot use ip as a temporary in this verification code. Due to the fact | 1249 // Cannot use ip as a temporary in this verification code. Due to the fact |
| 1255 // that ip is clobbered as part of cmp with an object Operand. | 1250 // that ip is clobbered as part of cmp with an object Operand. |
| 1256 push(holder_reg); // Temporarily save holder on the stack. | 1251 push(holder_reg); // Temporarily save holder on the stack. |
| 1257 // Read the first word and compare to the global_context_map. | 1252 // Read the first word and compare to the global_context_map. |
| 1258 ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); | 1253 ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); |
| 1259 LoadRoot(ip, Heap::kGlobalContextMapRootIndex); | 1254 LoadRoot(ip, Heap::kGlobalContextMapRootIndex); |
| 1260 cmp(holder_reg, ip); | 1255 cmp(holder_reg, ip); |
| 1261 Check(eq, "JSGlobalObject::global_context should be a global context."); | 1256 Check(eq, "JSGlobalObject::global_context should be a global context."); |
| 1262 pop(holder_reg); // Restore holder. | 1257 pop(holder_reg); // Restore holder. |
| 1263 } | 1258 } |
| 1264 | 1259 |
| 1265 // Check if both contexts are the same. | 1260 // Check if both contexts are the same. |
| 1266 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); | 1261 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
| 1267 cmp(scratch, Operand(ip)); | 1262 cmp(scratch, Operand(ip)); |
| 1268 b(eq, &same_contexts); | 1263 b(eq, &same_contexts); |
| 1269 | 1264 |
| 1270 // Check the context is a global context. | 1265 // Check the context is a global context. |
| 1271 if (FLAG_debug_code) { | 1266 if (emit_debug_code()) { |
| 1272 // TODO(119): avoid push(holder_reg)/pop(holder_reg) | 1267 // TODO(119): avoid push(holder_reg)/pop(holder_reg) |
| 1273 // Cannot use ip as a temporary in this verification code. Due to the fact | 1268 // Cannot use ip as a temporary in this verification code. Due to the fact |
| 1274 // that ip is clobbered as part of cmp with an object Operand. | 1269 // that ip is clobbered as part of cmp with an object Operand. |
| 1275 push(holder_reg); // Temporarily save holder on the stack. | 1270 push(holder_reg); // Temporarily save holder on the stack. |
| 1276 mov(holder_reg, ip); // Move ip to its holding place. | 1271 mov(holder_reg, ip); // Move ip to its holding place. |
| 1277 LoadRoot(ip, Heap::kNullValueRootIndex); | 1272 LoadRoot(ip, Heap::kNullValueRootIndex); |
| 1278 cmp(holder_reg, ip); | 1273 cmp(holder_reg, ip); |
| 1279 Check(ne, "JSGlobalProxy::context() should not be null."); | 1274 Check(ne, "JSGlobalProxy::context() should not be null."); |
| 1280 | 1275 |
| 1281 ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); | 1276 ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1303 } | 1298 } |
| 1304 | 1299 |
| 1305 | 1300 |
| 1306 void MacroAssembler::AllocateInNewSpace(int object_size, | 1301 void MacroAssembler::AllocateInNewSpace(int object_size, |
| 1307 Register result, | 1302 Register result, |
| 1308 Register scratch1, | 1303 Register scratch1, |
| 1309 Register scratch2, | 1304 Register scratch2, |
| 1310 Label* gc_required, | 1305 Label* gc_required, |
| 1311 AllocationFlags flags) { | 1306 AllocationFlags flags) { |
| 1312 if (!FLAG_inline_new) { | 1307 if (!FLAG_inline_new) { |
| 1313 if (FLAG_debug_code) { | 1308 if (emit_debug_code()) { |
| 1314 // Trash the registers to simulate an allocation failure. | 1309 // Trash the registers to simulate an allocation failure. |
| 1315 mov(result, Operand(0x7091)); | 1310 mov(result, Operand(0x7091)); |
| 1316 mov(scratch1, Operand(0x7191)); | 1311 mov(scratch1, Operand(0x7191)); |
| 1317 mov(scratch2, Operand(0x7291)); | 1312 mov(scratch2, Operand(0x7291)); |
| 1318 } | 1313 } |
| 1319 jmp(gc_required); | 1314 jmp(gc_required); |
| 1320 return; | 1315 return; |
| 1321 } | 1316 } |
| 1322 | 1317 |
| 1323 ASSERT(!result.is(scratch1)); | 1318 ASSERT(!result.is(scratch1)); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1352 Register obj_size_reg = scratch2; | 1347 Register obj_size_reg = scratch2; |
| 1353 mov(topaddr, Operand(new_space_allocation_top)); | 1348 mov(topaddr, Operand(new_space_allocation_top)); |
| 1354 mov(obj_size_reg, Operand(object_size)); | 1349 mov(obj_size_reg, Operand(object_size)); |
| 1355 | 1350 |
| 1356 // This code stores a temporary value in ip. This is OK, as the code below | 1351 // This code stores a temporary value in ip. This is OK, as the code below |
| 1357 // does not need ip for implicit literal generation. | 1352 // does not need ip for implicit literal generation. |
| 1358 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1353 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 1359 // Load allocation top into result and allocation limit into ip. | 1354 // Load allocation top into result and allocation limit into ip. |
| 1360 ldm(ia, topaddr, result.bit() | ip.bit()); | 1355 ldm(ia, topaddr, result.bit() | ip.bit()); |
| 1361 } else { | 1356 } else { |
| 1362 if (FLAG_debug_code) { | 1357 if (emit_debug_code()) { |
| 1363 // Assert that result actually contains top on entry. ip is used | 1358 // Assert that result actually contains top on entry. ip is used |
| 1364 // immediately below so this use of ip does not cause difference with | 1359 // immediately below so this use of ip does not cause difference with |
| 1365 // respect to register content between debug and release mode. | 1360 // respect to register content between debug and release mode. |
| 1366 ldr(ip, MemOperand(topaddr)); | 1361 ldr(ip, MemOperand(topaddr)); |
| 1367 cmp(result, ip); | 1362 cmp(result, ip); |
| 1368 Check(eq, "Unexpected allocation top"); | 1363 Check(eq, "Unexpected allocation top"); |
| 1369 } | 1364 } |
| 1370 // Load allocation limit into ip. Result already contains allocation top. | 1365 // Load allocation limit into ip. Result already contains allocation top. |
| 1371 ldr(ip, MemOperand(topaddr, limit - top)); | 1366 ldr(ip, MemOperand(topaddr, limit - top)); |
| 1372 } | 1367 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1386 } | 1381 } |
| 1387 | 1382 |
| 1388 | 1383 |
| 1389 void MacroAssembler::AllocateInNewSpace(Register object_size, | 1384 void MacroAssembler::AllocateInNewSpace(Register object_size, |
| 1390 Register result, | 1385 Register result, |
| 1391 Register scratch1, | 1386 Register scratch1, |
| 1392 Register scratch2, | 1387 Register scratch2, |
| 1393 Label* gc_required, | 1388 Label* gc_required, |
| 1394 AllocationFlags flags) { | 1389 AllocationFlags flags) { |
| 1395 if (!FLAG_inline_new) { | 1390 if (!FLAG_inline_new) { |
| 1396 if (FLAG_debug_code) { | 1391 if (emit_debug_code()) { |
| 1397 // Trash the registers to simulate an allocation failure. | 1392 // Trash the registers to simulate an allocation failure. |
| 1398 mov(result, Operand(0x7091)); | 1393 mov(result, Operand(0x7091)); |
| 1399 mov(scratch1, Operand(0x7191)); | 1394 mov(scratch1, Operand(0x7191)); |
| 1400 mov(scratch2, Operand(0x7291)); | 1395 mov(scratch2, Operand(0x7291)); |
| 1401 } | 1396 } |
| 1402 jmp(gc_required); | 1397 jmp(gc_required); |
| 1403 return; | 1398 return; |
| 1404 } | 1399 } |
| 1405 | 1400 |
| 1406 // Assert that the register arguments are different and that none of | 1401 // Assert that the register arguments are different and that none of |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1430 // Set up allocation top address. | 1425 // Set up allocation top address. |
| 1431 Register topaddr = scratch1; | 1426 Register topaddr = scratch1; |
| 1432 mov(topaddr, Operand(new_space_allocation_top)); | 1427 mov(topaddr, Operand(new_space_allocation_top)); |
| 1433 | 1428 |
| 1434 // This code stores a temporary value in ip. This is OK, as the code below | 1429 // This code stores a temporary value in ip. This is OK, as the code below |
| 1435 // does not need ip for implicit literal generation. | 1430 // does not need ip for implicit literal generation. |
| 1436 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1431 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 1437 // Load allocation top into result and allocation limit into ip. | 1432 // Load allocation top into result and allocation limit into ip. |
| 1438 ldm(ia, topaddr, result.bit() | ip.bit()); | 1433 ldm(ia, topaddr, result.bit() | ip.bit()); |
| 1439 } else { | 1434 } else { |
| 1440 if (FLAG_debug_code) { | 1435 if (emit_debug_code()) { |
| 1441 // Assert that result actually contains top on entry. ip is used | 1436 // Assert that result actually contains top on entry. ip is used |
| 1442 // immediately below so this use of ip does not cause difference with | 1437 // immediately below so this use of ip does not cause difference with |
| 1443 // respect to register content between debug and release mode. | 1438 // respect to register content between debug and release mode. |
| 1444 ldr(ip, MemOperand(topaddr)); | 1439 ldr(ip, MemOperand(topaddr)); |
| 1445 cmp(result, ip); | 1440 cmp(result, ip); |
| 1446 Check(eq, "Unexpected allocation top"); | 1441 Check(eq, "Unexpected allocation top"); |
| 1447 } | 1442 } |
| 1448 // Load allocation limit into ip. Result already contains allocation top. | 1443 // Load allocation limit into ip. Result already contains allocation top. |
| 1449 ldr(ip, MemOperand(topaddr, limit - top)); | 1444 ldr(ip, MemOperand(topaddr, limit - top)); |
| 1450 } | 1445 } |
| 1451 | 1446 |
| 1452 // Calculate new top and bail out if new space is exhausted. Use result | 1447 // Calculate new top and bail out if new space is exhausted. Use result |
| 1453 // to calculate the new top. Object size may be in words so a shift is | 1448 // to calculate the new top. Object size may be in words so a shift is |
| 1454 // required to get the number of bytes. | 1449 // required to get the number of bytes. |
| 1455 if ((flags & SIZE_IN_WORDS) != 0) { | 1450 if ((flags & SIZE_IN_WORDS) != 0) { |
| 1456 add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC); | 1451 add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC); |
| 1457 } else { | 1452 } else { |
| 1458 add(scratch2, result, Operand(object_size), SetCC); | 1453 add(scratch2, result, Operand(object_size), SetCC); |
| 1459 } | 1454 } |
| 1460 b(cs, gc_required); | 1455 b(cs, gc_required); |
| 1461 cmp(scratch2, Operand(ip)); | 1456 cmp(scratch2, Operand(ip)); |
| 1462 b(hi, gc_required); | 1457 b(hi, gc_required); |
| 1463 | 1458 |
| 1464 // Update allocation top. result temporarily holds the new top. | 1459 // Update allocation top. result temporarily holds the new top. |
| 1465 if (FLAG_debug_code) { | 1460 if (emit_debug_code()) { |
| 1466 tst(scratch2, Operand(kObjectAlignmentMask)); | 1461 tst(scratch2, Operand(kObjectAlignmentMask)); |
| 1467 Check(eq, "Unaligned allocation in new space"); | 1462 Check(eq, "Unaligned allocation in new space"); |
| 1468 } | 1463 } |
| 1469 str(scratch2, MemOperand(topaddr)); | 1464 str(scratch2, MemOperand(topaddr)); |
| 1470 | 1465 |
| 1471 // Tag object if requested. | 1466 // Tag object if requested. |
| 1472 if ((flags & TAG_OBJECT) != 0) { | 1467 if ((flags & TAG_OBJECT) != 0) { |
| 1473 add(result, result, Operand(kHeapObjectTag)); | 1468 add(result, result, Operand(kHeapObjectTag)); |
| 1474 } | 1469 } |
| 1475 } | 1470 } |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1759 | 1754 |
| 1760 // If result is non-zero, dereference to get the result value | 1755 // If result is non-zero, dereference to get the result value |
| 1761 // otherwise set it to undefined. | 1756 // otherwise set it to undefined. |
| 1762 cmp(r0, Operand(0)); | 1757 cmp(r0, Operand(0)); |
| 1763 LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 1758 LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
| 1764 ldr(r0, MemOperand(r0), ne); | 1759 ldr(r0, MemOperand(r0), ne); |
| 1765 | 1760 |
| 1766 // No more valid handles (the result handle was the last one). Restore | 1761 // No more valid handles (the result handle was the last one). Restore |
| 1767 // previous handle scope. | 1762 // previous handle scope. |
| 1768 str(r4, MemOperand(r7, kNextOffset)); | 1763 str(r4, MemOperand(r7, kNextOffset)); |
| 1769 if (FLAG_debug_code) { | 1764 if (emit_debug_code()) { |
| 1770 ldr(r1, MemOperand(r7, kLevelOffset)); | 1765 ldr(r1, MemOperand(r7, kLevelOffset)); |
| 1771 cmp(r1, r6); | 1766 cmp(r1, r6); |
| 1772 Check(eq, "Unexpected level after return from api call"); | 1767 Check(eq, "Unexpected level after return from api call"); |
| 1773 } | 1768 } |
| 1774 sub(r6, r6, Operand(1)); | 1769 sub(r6, r6, Operand(1)); |
| 1775 str(r6, MemOperand(r7, kLevelOffset)); | 1770 str(r6, MemOperand(r7, kLevelOffset)); |
| 1776 ldr(ip, MemOperand(r7, kLimitOffset)); | 1771 ldr(ip, MemOperand(r7, kLimitOffset)); |
| 1777 cmp(r5, ip); | 1772 cmp(r5, ip); |
| 1778 b(ne, &delete_allocated_handles); | 1773 b(ne, &delete_allocated_handles); |
| 1779 | 1774 |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2032 | 2027 |
| 2033 // Retrieve FPSCR. | 2028 // Retrieve FPSCR. |
| 2034 vmrs(scratch); | 2029 vmrs(scratch); |
| 2035 // Restore FPSCR. | 2030 // Restore FPSCR. |
| 2036 vmsr(prev_fpscr); | 2031 vmsr(prev_fpscr); |
| 2037 // Check for vfp exceptions. | 2032 // Check for vfp exceptions. |
| 2038 tst(scratch, Operand(kVFPExceptionMask | check_inexact_conversion)); | 2033 tst(scratch, Operand(kVFPExceptionMask | check_inexact_conversion)); |
| 2039 } | 2034 } |
| 2040 | 2035 |
| 2041 | 2036 |
| 2037 void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result, |
| 2038 Register input_high, |
| 2039 Register input_low, |
| 2040 Register scratch) { |
| 2041 Label done, normal_exponent, restore_sign; |
| 2042 |
| 2043 // Extract the biased exponent in result. |
| 2044 Ubfx(result, |
| 2045 input_high, |
| 2046 HeapNumber::kExponentShift, |
| 2047 HeapNumber::kExponentBits); |
| 2048 |
| 2049 // Check for Infinity and NaNs, which should return 0. |
| 2050 cmp(result, Operand(HeapNumber::kExponentMask)); |
| 2051 mov(result, Operand(0), LeaveCC, eq); |
| 2052 b(eq, &done); |
| 2053 |
| 2054 // Express exponent as delta to (number of mantissa bits + 31). |
| 2055 sub(result, |
| 2056 result, |
| 2057 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31), |
| 2058 SetCC); |
| 2059 |
| 2060 // If the delta is strictly positive, all bits would be shifted away, |
| 2061 // which means that we can return 0. |
| 2062 b(le, &normal_exponent); |
| 2063 mov(result, Operand(0)); |
| 2064 b(&done); |
| 2065 |
| 2066 bind(&normal_exponent); |
| 2067 const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1; |
| 2068 // Calculate shift. |
| 2069 add(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits), SetCC); |
| 2070 |
| 2071 // Save the sign. |
| 2072 Register sign = result; |
| 2073 result = no_reg; |
| 2074 and_(sign, input_high, Operand(HeapNumber::kSignMask)); |
| 2075 |
| 2076 // Set the implicit 1 before the mantissa part in input_high. |
| 2077 orr(input_high, |
| 2078 input_high, |
| 2079 Operand(1 << HeapNumber::kMantissaBitsInTopWord)); |
| 2080 // Shift the mantissa bits to the correct position. |
| 2081 // We don't need to clear non-mantissa bits as they will be shifted away. |
| 2082 // If they weren't, it would mean that the answer is in the 32bit range. |
| 2083 mov(input_high, Operand(input_high, LSL, scratch)); |
| 2084 |
| 2085 // Replace the shifted bits with bits from the lower mantissa word. |
| 2086 Label pos_shift, shift_done; |
| 2087 rsb(scratch, scratch, Operand(32), SetCC); |
| 2088 b(&pos_shift, ge); |
| 2089 |
| 2090 // Negate scratch. |
| 2091 rsb(scratch, scratch, Operand(0)); |
| 2092 mov(input_low, Operand(input_low, LSL, scratch)); |
| 2093 b(&shift_done); |
| 2094 |
| 2095 bind(&pos_shift); |
| 2096 mov(input_low, Operand(input_low, LSR, scratch)); |
| 2097 |
| 2098 bind(&shift_done); |
| 2099 orr(input_high, input_high, Operand(input_low)); |
| 2100 // Restore sign if necessary. |
| 2101 cmp(sign, Operand(0)); |
| 2102 result = sign; |
| 2103 sign = no_reg; |
| 2104 rsb(result, input_high, Operand(0), LeaveCC, ne); |
| 2105 mov(result, input_high, LeaveCC, eq); |
| 2106 bind(&done); |
| 2107 } |
| 2108 |
| 2109 |
| 2110 void MacroAssembler::EmitECMATruncate(Register result, |
| 2111 DwVfpRegister double_input, |
| 2112 SwVfpRegister single_scratch, |
| 2113 Register scratch, |
| 2114 Register input_high, |
| 2115 Register input_low) { |
| 2116 CpuFeatures::Scope scope(VFP3); |
| 2117 ASSERT(!input_high.is(result)); |
| 2118 ASSERT(!input_low.is(result)); |
| 2119 ASSERT(!input_low.is(input_high)); |
| 2120 ASSERT(!scratch.is(result) && |
| 2121 !scratch.is(input_high) && |
| 2122 !scratch.is(input_low)); |
| 2123 ASSERT(!single_scratch.is(double_input.low()) && |
| 2124 !single_scratch.is(double_input.high())); |
| 2125 |
| 2126 Label done; |
| 2127 |
| 2128 // Clear cumulative exception flags. |
| 2129 ClearFPSCRBits(kVFPExceptionMask, scratch); |
| 2130 // Try a conversion to a signed integer. |
| 2131 vcvt_s32_f64(single_scratch, double_input); |
| 2132 vmov(result, single_scratch); |
| 2133 // Retrieve he FPSCR. |
| 2134 vmrs(scratch); |
| 2135 // Check for overflow and NaNs. |
| 2136 tst(scratch, Operand(kVFPOverflowExceptionBit | |
| 2137 kVFPUnderflowExceptionBit | |
| 2138 kVFPInvalidOpExceptionBit)); |
| 2139 // If we had no exceptions we are done. |
| 2140 b(eq, &done); |
| 2141 |
| 2142 // Load the double value and perform a manual truncation. |
| 2143 vmov(input_low, input_high, double_input); |
| 2144 EmitOutOfInt32RangeTruncate(result, |
| 2145 input_high, |
| 2146 input_low, |
| 2147 scratch); |
| 2148 bind(&done); |
| 2149 } |
| 2150 |
| 2151 |
| 2042 void MacroAssembler::GetLeastBitsFromSmi(Register dst, | 2152 void MacroAssembler::GetLeastBitsFromSmi(Register dst, |
| 2043 Register src, | 2153 Register src, |
| 2044 int num_least_bits) { | 2154 int num_least_bits) { |
| 2045 if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) { | 2155 if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) { |
| 2046 ubfx(dst, src, kSmiTagSize, num_least_bits); | 2156 ubfx(dst, src, kSmiTagSize, num_least_bits); |
| 2047 } else { | 2157 } else { |
| 2048 mov(dst, Operand(src, ASR, kSmiTagSize)); | 2158 mov(dst, Operand(src, ASR, kSmiTagSize)); |
| 2049 and_(dst, dst, Operand((1 << num_least_bits) - 1)); | 2159 and_(dst, dst, Operand((1 << num_least_bits) - 1)); |
| 2050 } | 2160 } |
| 2051 } | 2161 } |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2221 if (FLAG_native_code_counters && counter->Enabled()) { | 2331 if (FLAG_native_code_counters && counter->Enabled()) { |
| 2222 mov(scratch2, Operand(ExternalReference(counter))); | 2332 mov(scratch2, Operand(ExternalReference(counter))); |
| 2223 ldr(scratch1, MemOperand(scratch2)); | 2333 ldr(scratch1, MemOperand(scratch2)); |
| 2224 sub(scratch1, scratch1, Operand(value)); | 2334 sub(scratch1, scratch1, Operand(value)); |
| 2225 str(scratch1, MemOperand(scratch2)); | 2335 str(scratch1, MemOperand(scratch2)); |
| 2226 } | 2336 } |
| 2227 } | 2337 } |
| 2228 | 2338 |
| 2229 | 2339 |
| 2230 void MacroAssembler::Assert(Condition cond, const char* msg) { | 2340 void MacroAssembler::Assert(Condition cond, const char* msg) { |
| 2231 if (FLAG_debug_code) | 2341 if (emit_debug_code()) |
| 2232 Check(cond, msg); | 2342 Check(cond, msg); |
| 2233 } | 2343 } |
| 2234 | 2344 |
| 2235 | 2345 |
| 2236 void MacroAssembler::AssertRegisterIsRoot(Register reg, | 2346 void MacroAssembler::AssertRegisterIsRoot(Register reg, |
| 2237 Heap::RootListIndex index) { | 2347 Heap::RootListIndex index) { |
| 2238 if (FLAG_debug_code) { | 2348 if (emit_debug_code()) { |
| 2239 LoadRoot(ip, index); | 2349 LoadRoot(ip, index); |
| 2240 cmp(reg, ip); | 2350 cmp(reg, ip); |
| 2241 Check(eq, "Register did not match expected root"); | 2351 Check(eq, "Register did not match expected root"); |
| 2242 } | 2352 } |
| 2243 } | 2353 } |
| 2244 | 2354 |
| 2245 | 2355 |
| 2246 void MacroAssembler::AssertFastElements(Register elements) { | 2356 void MacroAssembler::AssertFastElements(Register elements) { |
| 2247 if (FLAG_debug_code) { | 2357 if (emit_debug_code()) { |
| 2248 ASSERT(!elements.is(ip)); | 2358 ASSERT(!elements.is(ip)); |
| 2249 Label ok; | 2359 Label ok; |
| 2250 push(elements); | 2360 push(elements); |
| 2251 ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); | 2361 ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 2252 LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 2362 LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 2253 cmp(elements, ip); | 2363 cmp(elements, ip); |
| 2254 b(eq, &ok); | 2364 b(eq, &ok); |
| 2255 LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); | 2365 LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); |
| 2256 cmp(elements, ip); | 2366 cmp(elements, ip); |
| 2257 b(eq, &ok); | 2367 b(eq, &ok); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2325 // Slot is in the current function context. Move it into the | 2435 // Slot is in the current function context. Move it into the |
| 2326 // destination register in case we store into it (the write barrier | 2436 // destination register in case we store into it (the write barrier |
| 2327 // cannot be allowed to destroy the context in esi). | 2437 // cannot be allowed to destroy the context in esi). |
| 2328 mov(dst, cp); | 2438 mov(dst, cp); |
| 2329 } | 2439 } |
| 2330 | 2440 |
| 2331 // We should not have found a 'with' context by walking the context chain | 2441 // We should not have found a 'with' context by walking the context chain |
| 2332 // (i.e., the static scope chain and runtime context chain do not agree). | 2442 // (i.e., the static scope chain and runtime context chain do not agree). |
| 2333 // A variable occurring in such a scope should have slot type LOOKUP and | 2443 // A variable occurring in such a scope should have slot type LOOKUP and |
| 2334 // not CONTEXT. | 2444 // not CONTEXT. |
| 2335 if (FLAG_debug_code) { | 2445 if (emit_debug_code()) { |
| 2336 ldr(ip, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 2446 ldr(ip, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); |
| 2337 cmp(dst, ip); | 2447 cmp(dst, ip); |
| 2338 Check(eq, "Yo dawg, I heard you liked function contexts " | 2448 Check(eq, "Yo dawg, I heard you liked function contexts " |
| 2339 "so I put function contexts in all your contexts"); | 2449 "so I put function contexts in all your contexts"); |
| 2340 } | 2450 } |
| 2341 } | 2451 } |
| 2342 | 2452 |
| 2343 | 2453 |
| 2344 void MacroAssembler::LoadGlobalFunction(int index, Register function) { | 2454 void MacroAssembler::LoadGlobalFunction(int index, Register function) { |
| 2345 // Load the global or builtins object from the current context. | 2455 // Load the global or builtins object from the current context. |
| 2346 ldr(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); | 2456 ldr(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2347 // Load the global context from the global or builtins object. | 2457 // Load the global context from the global or builtins object. |
| 2348 ldr(function, FieldMemOperand(function, | 2458 ldr(function, FieldMemOperand(function, |
| 2349 GlobalObject::kGlobalContextOffset)); | 2459 GlobalObject::kGlobalContextOffset)); |
| 2350 // Load the function from the global context. | 2460 // Load the function from the global context. |
| 2351 ldr(function, MemOperand(function, Context::SlotOffset(index))); | 2461 ldr(function, MemOperand(function, Context::SlotOffset(index))); |
| 2352 } | 2462 } |
| 2353 | 2463 |
| 2354 | 2464 |
| 2355 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, | 2465 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, |
| 2356 Register map, | 2466 Register map, |
| 2357 Register scratch) { | 2467 Register scratch) { |
| 2358 // Load the initial map. The global functions all have initial maps. | 2468 // Load the initial map. The global functions all have initial maps. |
| 2359 ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 2469 ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 2360 if (FLAG_debug_code) { | 2470 if (emit_debug_code()) { |
| 2361 Label ok, fail; | 2471 Label ok, fail; |
| 2362 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); | 2472 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); |
| 2363 b(&ok); | 2473 b(&ok); |
| 2364 bind(&fail); | 2474 bind(&fail); |
| 2365 Abort("Global functions must have initial map"); | 2475 Abort("Global functions must have initial map"); |
| 2366 bind(&ok); | 2476 bind(&ok); |
| 2367 } | 2477 } |
| 2368 } | 2478 } |
| 2369 | 2479 |
| 2370 | 2480 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2558 bind(&align_loop_1); | 2668 bind(&align_loop_1); |
| 2559 tst(src, Operand(kPointerSize - 1)); | 2669 tst(src, Operand(kPointerSize - 1)); |
| 2560 b(eq, &word_loop); | 2670 b(eq, &word_loop); |
| 2561 ldrb(scratch, MemOperand(src, 1, PostIndex)); | 2671 ldrb(scratch, MemOperand(src, 1, PostIndex)); |
| 2562 strb(scratch, MemOperand(dst, 1, PostIndex)); | 2672 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| 2563 sub(length, length, Operand(1), SetCC); | 2673 sub(length, length, Operand(1), SetCC); |
| 2564 b(ne, &byte_loop_1); | 2674 b(ne, &byte_loop_1); |
| 2565 | 2675 |
| 2566 // Copy bytes in word size chunks. | 2676 // Copy bytes in word size chunks. |
| 2567 bind(&word_loop); | 2677 bind(&word_loop); |
| 2568 if (FLAG_debug_code) { | 2678 if (emit_debug_code()) { |
| 2569 tst(src, Operand(kPointerSize - 1)); | 2679 tst(src, Operand(kPointerSize - 1)); |
| 2570 Assert(eq, "Expecting alignment for CopyBytes"); | 2680 Assert(eq, "Expecting alignment for CopyBytes"); |
| 2571 } | 2681 } |
| 2572 cmp(length, Operand(kPointerSize)); | 2682 cmp(length, Operand(kPointerSize)); |
| 2573 b(lt, &byte_loop); | 2683 b(lt, &byte_loop); |
| 2574 ldr(scratch, MemOperand(src, kPointerSize, PostIndex)); | 2684 ldr(scratch, MemOperand(src, kPointerSize, PostIndex)); |
| 2575 #if CAN_USE_UNALIGNED_ACCESSES | 2685 #if CAN_USE_UNALIGNED_ACCESSES |
| 2576 str(scratch, MemOperand(dst, kPointerSize, PostIndex)); | 2686 str(scratch, MemOperand(dst, kPointerSize, PostIndex)); |
| 2577 #else | 2687 #else |
| 2578 strb(scratch, MemOperand(dst, 1, PostIndex)); | 2688 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2718 // Push Isolate address on the stack after the arguments. | 2828 // Push Isolate address on the stack after the arguments. |
| 2719 mov(scratch, Operand(ExternalReference::isolate_address())); | 2829 mov(scratch, Operand(ExternalReference::isolate_address())); |
| 2720 str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); | 2830 str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); |
| 2721 } | 2831 } |
| 2722 num_arguments += 1; | 2832 num_arguments += 1; |
| 2723 | 2833 |
| 2724 // Make sure that the stack is aligned before calling a C function unless | 2834 // Make sure that the stack is aligned before calling a C function unless |
| 2725 // running in the simulator. The simulator has its own alignment check which | 2835 // running in the simulator. The simulator has its own alignment check which |
| 2726 // provides more information. | 2836 // provides more information. |
| 2727 #if defined(V8_HOST_ARCH_ARM) | 2837 #if defined(V8_HOST_ARCH_ARM) |
| 2728 if (FLAG_debug_code) { | 2838 if (emit_debug_code()) { |
| 2729 int frame_alignment = OS::ActivationFrameAlignment(); | 2839 int frame_alignment = OS::ActivationFrameAlignment(); |
| 2730 int frame_alignment_mask = frame_alignment - 1; | 2840 int frame_alignment_mask = frame_alignment - 1; |
| 2731 if (frame_alignment > kPointerSize) { | 2841 if (frame_alignment > kPointerSize) { |
| 2732 ASSERT(IsPowerOf2(frame_alignment)); | 2842 ASSERT(IsPowerOf2(frame_alignment)); |
| 2733 Label alignment_as_expected; | 2843 Label alignment_as_expected; |
| 2734 tst(sp, Operand(frame_alignment_mask)); | 2844 tst(sp, Operand(frame_alignment_mask)); |
| 2735 b(eq, &alignment_as_expected); | 2845 b(eq, &alignment_as_expected); |
| 2736 // Don't use Check here, as it will call Runtime_Abort possibly | 2846 // Don't use Check here, as it will call Runtime_Abort possibly |
| 2737 // re-entering here. | 2847 // re-entering here. |
| 2738 stop("Unexpected alignment"); | 2848 stop("Unexpected alignment"); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2757 add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); | 2867 add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); |
| 2758 } | 2868 } |
| 2759 } | 2869 } |
| 2760 | 2870 |
| 2761 | 2871 |
| 2762 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, | 2872 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, |
| 2763 Register result) { | 2873 Register result) { |
| 2764 const uint32_t kLdrOffsetMask = (1 << 12) - 1; | 2874 const uint32_t kLdrOffsetMask = (1 << 12) - 1; |
| 2765 const int32_t kPCRegOffset = 2 * kPointerSize; | 2875 const int32_t kPCRegOffset = 2 * kPointerSize; |
| 2766 ldr(result, MemOperand(ldr_location)); | 2876 ldr(result, MemOperand(ldr_location)); |
| 2767 if (FLAG_debug_code) { | 2877 if (emit_debug_code()) { |
| 2768 // Check that the instruction is a ldr reg, [pc + offset] . | 2878 // Check that the instruction is a ldr reg, [pc + offset] . |
| 2769 and_(result, result, Operand(kLdrPCPattern)); | 2879 and_(result, result, Operand(kLdrPCPattern)); |
| 2770 cmp(result, Operand(kLdrPCPattern)); | 2880 cmp(result, Operand(kLdrPCPattern)); |
| 2771 Check(eq, "The instruction to patch should be a load from pc."); | 2881 Check(eq, "The instruction to patch should be a load from pc."); |
| 2772 // Result was clobbered. Restore it. | 2882 // Result was clobbered. Restore it. |
| 2773 ldr(result, MemOperand(ldr_location)); | 2883 ldr(result, MemOperand(ldr_location)); |
| 2774 } | 2884 } |
| 2775 // Get the address of the constant. | 2885 // Get the address of the constant. |
| 2776 and_(result, result, Operand(kLdrOffsetMask)); | 2886 and_(result, result, Operand(kLdrOffsetMask)); |
| 2777 add(result, ldr_location, Operand(result)); | 2887 add(result, ldr_location, Operand(result)); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2814 void CodePatcher::EmitCondition(Condition cond) { | 2924 void CodePatcher::EmitCondition(Condition cond) { |
| 2815 Instr instr = Assembler::instr_at(masm_.pc_); | 2925 Instr instr = Assembler::instr_at(masm_.pc_); |
| 2816 instr = (instr & ~kCondMask) | cond; | 2926 instr = (instr & ~kCondMask) | cond; |
| 2817 masm_.emit(instr); | 2927 masm_.emit(instr); |
| 2818 } | 2928 } |
| 2819 | 2929 |
| 2820 | 2930 |
| 2821 } } // namespace v8::internal | 2931 } } // namespace v8::internal |
| 2822 | 2932 |
| 2823 #endif // V8_TARGET_ARCH_ARM | 2933 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |