OLD | NEW |
1 | |
2 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
3 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
4 // found in the LICENSE file. | 3 // found in the LICENSE file. |
5 | 4 |
6 #include "src/v8.h" | 5 #include "src/v8.h" |
7 | 6 |
8 #include "src/codegen.h" | 7 #include "src/codegen.h" |
9 #include "src/deoptimizer.h" | 8 #include "src/deoptimizer.h" |
10 #include "src/full-codegen.h" | 9 #include "src/full-codegen.h" |
11 #include "src/safepoint-table.h" | 10 #include "src/safepoint-table.h" |
12 | 11 |
13 namespace v8 { | 12 namespace v8 { |
14 namespace internal { | 13 namespace internal { |
15 | 14 |
16 | 15 |
17 int Deoptimizer::patch_size() { | 16 int Deoptimizer::patch_size() { |
18 const int kCallInstructionSizeInWords = 4; | 17 const int kCallInstructionSizeInWords = 6; |
19 return kCallInstructionSizeInWords * Assembler::kInstrSize; | 18 return kCallInstructionSizeInWords * Assembler::kInstrSize; |
20 } | 19 } |
21 | 20 |
22 | 21 |
23 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { | 22 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { |
24 Address code_start_address = code->instruction_start(); | 23 Address code_start_address = code->instruction_start(); |
25 // Invalidate the relocation information, as it will become invalid by the | 24 // Invalidate the relocation information, as it will become invalid by the |
26 // code patching below, and is not needed any more. | 25 // code patching below, and is not needed any more. |
27 code->InvalidateRelocation(); | 26 code->InvalidateRelocation(); |
28 | 27 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 input_->SetRegister(i, i * 4); | 86 input_->SetRegister(i, i * 4); |
88 } | 87 } |
89 input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp())); | 88 input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp())); |
90 input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp())); | 89 input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp())); |
91 for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) { | 90 for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) { |
92 input_->SetDoubleRegister(i, 0.0); | 91 input_->SetDoubleRegister(i, 0.0); |
93 } | 92 } |
94 | 93 |
95 // Fill the frame content from the actual data on the frame. | 94 // Fill the frame content from the actual data on the frame. |
96 for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) { | 95 for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) { |
97 input_->SetFrameSlot(i, Memory::uint32_at(tos + i)); | 96 input_->SetFrameSlot(i, Memory::uint64_at(tos + i)); |
98 } | 97 } |
99 } | 98 } |
100 | 99 |
101 | 100 |
102 void Deoptimizer::SetPlatformCompiledStubRegisters( | 101 void Deoptimizer::SetPlatformCompiledStubRegisters( |
103 FrameDescription* output_frame, CodeStubInterfaceDescriptor* descriptor) { | 102 FrameDescription* output_frame, CodeStubInterfaceDescriptor* descriptor) { |
104 ApiFunction function(descriptor->deoptimization_handler()); | 103 ApiFunction function(descriptor->deoptimization_handler()); |
105 ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_); | 104 ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_); |
106 intptr_t handler = reinterpret_cast<intptr_t>(xref.address()); | 105 intptr_t handler = reinterpret_cast<intptr_t>(xref.address()); |
107 int params = descriptor->GetHandlerParameterCount(); | 106 int params = descriptor->GetHandlerParameterCount(); |
(...skipping 29 matching lines...) Expand all Loading... |
137 // For the rest, there are gaps on the stack, so the offsets remain the same. | 136 // For the rest, there are gaps on the stack, so the offsets remain the same. |
138 const int kNumberOfRegisters = Register::kNumRegisters; | 137 const int kNumberOfRegisters = Register::kNumRegisters; |
139 | 138 |
140 RegList restored_regs = kJSCallerSaved | kCalleeSaved; | 139 RegList restored_regs = kJSCallerSaved | kCalleeSaved; |
141 RegList saved_regs = restored_regs | sp.bit() | ra.bit(); | 140 RegList saved_regs = restored_regs | sp.bit() | ra.bit(); |
142 | 141 |
143 const int kDoubleRegsSize = | 142 const int kDoubleRegsSize = |
144 kDoubleSize * FPURegister::kMaxNumAllocatableRegisters; | 143 kDoubleSize * FPURegister::kMaxNumAllocatableRegisters; |
145 | 144 |
146 // Save all FPU registers before messing with them. | 145 // Save all FPU registers before messing with them. |
147 __ Subu(sp, sp, Operand(kDoubleRegsSize)); | 146 __ Dsubu(sp, sp, Operand(kDoubleRegsSize)); |
148 for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) { | 147 for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) { |
149 FPURegister fpu_reg = FPURegister::FromAllocationIndex(i); | 148 FPURegister fpu_reg = FPURegister::FromAllocationIndex(i); |
150 int offset = i * kDoubleSize; | 149 int offset = i * kDoubleSize; |
151 __ sdc1(fpu_reg, MemOperand(sp, offset)); | 150 __ sdc1(fpu_reg, MemOperand(sp, offset)); |
152 } | 151 } |
153 | 152 |
154 // Push saved_regs (needed to populate FrameDescription::registers_). | 153 // Push saved_regs (needed to populate FrameDescription::registers_). |
155 // Leave gaps for other registers. | 154 // Leave gaps for other registers. |
156 __ Subu(sp, sp, kNumberOfRegisters * kPointerSize); | 155 __ Dsubu(sp, sp, kNumberOfRegisters * kPointerSize); |
157 for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) { | 156 for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) { |
158 if ((saved_regs & (1 << i)) != 0) { | 157 if ((saved_regs & (1 << i)) != 0) { |
159 __ sw(ToRegister(i), MemOperand(sp, kPointerSize * i)); | 158 __ sd(ToRegister(i), MemOperand(sp, kPointerSize * i)); |
160 } | 159 } |
161 } | 160 } |
162 | 161 |
163 const int kSavedRegistersAreaSize = | 162 const int kSavedRegistersAreaSize = |
164 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; | 163 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; |
165 | 164 |
166 // Get the bailout id from the stack. | 165 // Get the bailout id from the stack. |
167 __ lw(a2, MemOperand(sp, kSavedRegistersAreaSize)); | 166 __ ld(a2, MemOperand(sp, kSavedRegistersAreaSize)); |
168 | 167 |
169 // Get the address of the location in the code object (a3) (return | 168 // Get the address of the location in the code object (a3) (return |
170 // address for lazy deoptimization) and compute the fp-to-sp delta in | 169 // address for lazy deoptimization) and compute the fp-to-sp delta in |
171 // register t0. | 170 // register a4. |
172 __ mov(a3, ra); | 171 __ mov(a3, ra); |
173 // Correct one word for bailout id. | 172 // Correct one word for bailout id. |
174 __ Addu(t0, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); | 173 __ Daddu(a4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); |
175 | 174 |
176 __ Subu(t0, fp, t0); | 175 __ Dsubu(a4, fp, a4); |
177 | 176 |
178 // Allocate a new deoptimizer object. | 177 // Allocate a new deoptimizer object. |
179 // Pass four arguments in a0 to a3 and fifth & sixth arguments on stack. | 178 __ PrepareCallCFunction(6, a5); |
180 __ PrepareCallCFunction(6, t1); | 179 // Pass six arguments, according to O32 or n64 ABI. a0..a3 are same for both. |
181 __ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | |
182 __ li(a1, Operand(type())); // bailout type, | 180 __ li(a1, Operand(type())); // bailout type, |
| 181 __ ld(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
183 // a2: bailout id already loaded. | 182 // a2: bailout id already loaded. |
184 // a3: code address or 0 already loaded. | 183 // a3: code address or 0 already loaded. |
185 __ sw(t0, CFunctionArgumentOperand(5)); // Fp-to-sp delta. | 184 if (kMipsAbi == kN64) { |
186 __ li(t1, Operand(ExternalReference::isolate_address(isolate()))); | 185 // a4: already has fp-to-sp delta. |
187 __ sw(t1, CFunctionArgumentOperand(6)); // Isolate. | 186 __ li(a5, Operand(ExternalReference::isolate_address(isolate()))); |
| 187 } else { // O32 abi. |
| 188 // Pass four arguments in a0 to a3 and fifth & sixth arguments on stack. |
| 189 __ sd(a4, CFunctionArgumentOperand(5)); // Fp-to-sp delta. |
| 190 __ li(a5, Operand(ExternalReference::isolate_address(isolate()))); |
| 191 __ sd(a5, CFunctionArgumentOperand(6)); // Isolate. |
| 192 } |
188 // Call Deoptimizer::New(). | 193 // Call Deoptimizer::New(). |
189 { | 194 { |
190 AllowExternalCallThatCantCauseGC scope(masm()); | 195 AllowExternalCallThatCantCauseGC scope(masm()); |
191 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6); | 196 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6); |
192 } | 197 } |
193 | 198 |
194 // Preserve "deoptimizer" object in register v0 and get the input | 199 // Preserve "deoptimizer" object in register v0 and get the input |
195 // frame descriptor pointer to a1 (deoptimizer->input_); | 200 // frame descriptor pointer to a1 (deoptimizer->input_); |
196 // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below. | 201 // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below. |
197 __ mov(a0, v0); | 202 __ mov(a0, v0); |
198 __ lw(a1, MemOperand(v0, Deoptimizer::input_offset())); | 203 __ ld(a1, MemOperand(v0, Deoptimizer::input_offset())); |
199 | 204 |
200 // Copy core registers into FrameDescription::registers_[kNumRegisters]. | 205 // Copy core registers into FrameDescription::registers_[kNumRegisters]. |
201 ASSERT(Register::kNumRegisters == kNumberOfRegisters); | 206 ASSERT(Register::kNumRegisters == kNumberOfRegisters); |
202 for (int i = 0; i < kNumberOfRegisters; i++) { | 207 for (int i = 0; i < kNumberOfRegisters; i++) { |
203 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); | 208 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); |
204 if ((saved_regs & (1 << i)) != 0) { | 209 if ((saved_regs & (1 << i)) != 0) { |
205 __ lw(a2, MemOperand(sp, i * kPointerSize)); | 210 __ ld(a2, MemOperand(sp, i * kPointerSize)); |
206 __ sw(a2, MemOperand(a1, offset)); | 211 __ sd(a2, MemOperand(a1, offset)); |
207 } else if (FLAG_debug_code) { | 212 } else if (FLAG_debug_code) { |
208 __ li(a2, kDebugZapValue); | 213 __ li(a2, kDebugZapValue); |
209 __ sw(a2, MemOperand(a1, offset)); | 214 __ sd(a2, MemOperand(a1, offset)); |
210 } | 215 } |
211 } | 216 } |
212 | 217 |
213 int double_regs_offset = FrameDescription::double_registers_offset(); | 218 int double_regs_offset = FrameDescription::double_registers_offset(); |
214 // Copy FPU registers to | 219 // Copy FPU registers to |
215 // double_registers_[DoubleRegister::kNumAllocatableRegisters] | 220 // double_registers_[DoubleRegister::kNumAllocatableRegisters] |
216 for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) { | 221 for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) { |
217 int dst_offset = i * kDoubleSize + double_regs_offset; | 222 int dst_offset = i * kDoubleSize + double_regs_offset; |
218 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize; | 223 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize; |
219 __ ldc1(f0, MemOperand(sp, src_offset)); | 224 __ ldc1(f0, MemOperand(sp, src_offset)); |
220 __ sdc1(f0, MemOperand(a1, dst_offset)); | 225 __ sdc1(f0, MemOperand(a1, dst_offset)); |
221 } | 226 } |
222 | 227 |
223 // Remove the bailout id and the saved registers from the stack. | 228 // Remove the bailout id and the saved registers from the stack. |
224 __ Addu(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); | 229 __ Daddu(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); |
225 | 230 |
226 // Compute a pointer to the unwinding limit in register a2; that is | 231 // Compute a pointer to the unwinding limit in register a2; that is |
227 // the first stack slot not part of the input frame. | 232 // the first stack slot not part of the input frame. |
228 __ lw(a2, MemOperand(a1, FrameDescription::frame_size_offset())); | 233 __ ld(a2, MemOperand(a1, FrameDescription::frame_size_offset())); |
229 __ Addu(a2, a2, sp); | 234 __ Daddu(a2, a2, sp); |
230 | 235 |
231 // Unwind the stack down to - but not including - the unwinding | 236 // Unwind the stack down to - but not including - the unwinding |
232 // limit and copy the contents of the activation frame to the input | 237 // limit and copy the contents of the activation frame to the input |
233 // frame description. | 238 // frame description. |
234 __ Addu(a3, a1, Operand(FrameDescription::frame_content_offset())); | 239 __ Daddu(a3, a1, Operand(FrameDescription::frame_content_offset())); |
235 Label pop_loop; | 240 Label pop_loop; |
236 Label pop_loop_header; | 241 Label pop_loop_header; |
237 __ BranchShort(&pop_loop_header); | 242 __ BranchShort(&pop_loop_header); |
238 __ bind(&pop_loop); | 243 __ bind(&pop_loop); |
239 __ pop(t0); | 244 __ pop(a4); |
240 __ sw(t0, MemOperand(a3, 0)); | 245 __ sd(a4, MemOperand(a3, 0)); |
241 __ addiu(a3, a3, sizeof(uint32_t)); | 246 __ daddiu(a3, a3, sizeof(uint64_t)); |
242 __ bind(&pop_loop_header); | 247 __ bind(&pop_loop_header); |
243 __ BranchShort(&pop_loop, ne, a2, Operand(sp)); | 248 __ BranchShort(&pop_loop, ne, a2, Operand(sp)); |
244 | |
245 // Compute the output frame in the deoptimizer. | 249 // Compute the output frame in the deoptimizer. |
246 __ push(a0); // Preserve deoptimizer object across call. | 250 __ push(a0); // Preserve deoptimizer object across call. |
247 // a0: deoptimizer object; a1: scratch. | 251 // a0: deoptimizer object; a1: scratch. |
248 __ PrepareCallCFunction(1, a1); | 252 __ PrepareCallCFunction(1, a1); |
249 // Call Deoptimizer::ComputeOutputFrames(). | 253 // Call Deoptimizer::ComputeOutputFrames(). |
250 { | 254 { |
251 AllowExternalCallThatCantCauseGC scope(masm()); | 255 AllowExternalCallThatCantCauseGC scope(masm()); |
252 __ CallCFunction( | 256 __ CallCFunction( |
253 ExternalReference::compute_output_frames_function(isolate()), 1); | 257 ExternalReference::compute_output_frames_function(isolate()), 1); |
254 } | 258 } |
255 __ pop(a0); // Restore deoptimizer object (class Deoptimizer). | 259 __ pop(a0); // Restore deoptimizer object (class Deoptimizer). |
256 | 260 |
257 // Replace the current (input) frame with the output frames. | 261 // Replace the current (input) frame with the output frames. |
258 Label outer_push_loop, inner_push_loop, | 262 Label outer_push_loop, inner_push_loop, |
259 outer_loop_header, inner_loop_header; | 263 outer_loop_header, inner_loop_header; |
260 // Outer loop state: t0 = current "FrameDescription** output_", | 264 // Outer loop state: a4 = current "FrameDescription** output_", |
261 // a1 = one past the last FrameDescription**. | 265 // a1 = one past the last FrameDescription**. |
262 __ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset())); | 266 __ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset())); |
263 __ lw(t0, MemOperand(a0, Deoptimizer::output_offset())); // t0 is output_. | 267 __ ld(a4, MemOperand(a0, Deoptimizer::output_offset())); // a4 is output_. |
264 __ sll(a1, a1, kPointerSizeLog2); // Count to offset. | 268 __ dsll(a1, a1, kPointerSizeLog2); // Count to offset. |
265 __ addu(a1, t0, a1); // a1 = one past the last FrameDescription**. | 269 __ daddu(a1, a4, a1); // a1 = one past the last FrameDescription**. |
266 __ jmp(&outer_loop_header); | 270 __ jmp(&outer_loop_header); |
267 __ bind(&outer_push_loop); | 271 __ bind(&outer_push_loop); |
268 // Inner loop state: a2 = current FrameDescription*, a3 = loop index. | 272 // Inner loop state: a2 = current FrameDescription*, a3 = loop index. |
269 __ lw(a2, MemOperand(t0, 0)); // output_[ix] | 273 __ ld(a2, MemOperand(a4, 0)); // output_[ix] |
270 __ lw(a3, MemOperand(a2, FrameDescription::frame_size_offset())); | 274 __ ld(a3, MemOperand(a2, FrameDescription::frame_size_offset())); |
271 __ jmp(&inner_loop_header); | 275 __ jmp(&inner_loop_header); |
272 __ bind(&inner_push_loop); | 276 __ bind(&inner_push_loop); |
273 __ Subu(a3, a3, Operand(sizeof(uint32_t))); | 277 __ Dsubu(a3, a3, Operand(sizeof(uint64_t))); |
274 __ Addu(t2, a2, Operand(a3)); | 278 __ Daddu(a6, a2, Operand(a3)); |
275 __ lw(t3, MemOperand(t2, FrameDescription::frame_content_offset())); | 279 __ ld(a7, MemOperand(a6, FrameDescription::frame_content_offset())); |
276 __ push(t3); | 280 __ push(a7); |
277 __ bind(&inner_loop_header); | 281 __ bind(&inner_loop_header); |
278 __ BranchShort(&inner_push_loop, ne, a3, Operand(zero_reg)); | 282 __ BranchShort(&inner_push_loop, ne, a3, Operand(zero_reg)); |
279 | 283 |
280 __ Addu(t0, t0, Operand(kPointerSize)); | 284 __ Daddu(a4, a4, Operand(kPointerSize)); |
281 __ bind(&outer_loop_header); | 285 __ bind(&outer_loop_header); |
282 __ BranchShort(&outer_push_loop, lt, t0, Operand(a1)); | 286 __ BranchShort(&outer_push_loop, lt, a4, Operand(a1)); |
283 | 287 |
284 __ lw(a1, MemOperand(a0, Deoptimizer::input_offset())); | 288 __ ld(a1, MemOperand(a0, Deoptimizer::input_offset())); |
285 for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) { | 289 for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) { |
286 const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i); | 290 const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i); |
287 int src_offset = i * kDoubleSize + double_regs_offset; | 291 int src_offset = i * kDoubleSize + double_regs_offset; |
288 __ ldc1(fpu_reg, MemOperand(a1, src_offset)); | 292 __ ldc1(fpu_reg, MemOperand(a1, src_offset)); |
289 } | 293 } |
290 | 294 |
291 // Push state, pc, and continuation from the last output frame. | 295 // Push state, pc, and continuation from the last output frame. |
292 __ lw(t2, MemOperand(a2, FrameDescription::state_offset())); | 296 __ ld(a6, MemOperand(a2, FrameDescription::state_offset())); |
293 __ push(t2); | 297 __ push(a6); |
294 | 298 |
295 __ lw(t2, MemOperand(a2, FrameDescription::pc_offset())); | 299 __ ld(a6, MemOperand(a2, FrameDescription::pc_offset())); |
296 __ push(t2); | 300 __ push(a6); |
297 __ lw(t2, MemOperand(a2, FrameDescription::continuation_offset())); | 301 __ ld(a6, MemOperand(a2, FrameDescription::continuation_offset())); |
298 __ push(t2); | 302 __ push(a6); |
299 | 303 |
300 | 304 |
301 // Technically restoring 'at' should work unless zero_reg is also restored | 305 // Technically restoring 'at' should work unless zero_reg is also restored |
302 // but it's safer to check for this. | 306 // but it's safer to check for this. |
303 ASSERT(!(at.bit() & restored_regs)); | 307 ASSERT(!(at.bit() & restored_regs)); |
304 // Restore the registers from the last output frame. | 308 // Restore the registers from the last output frame. |
305 __ mov(at, a2); | 309 __ mov(at, a2); |
306 for (int i = kNumberOfRegisters - 1; i >= 0; i--) { | 310 for (int i = kNumberOfRegisters - 1; i >= 0; i--) { |
307 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); | 311 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); |
308 if ((restored_regs & (1 << i)) != 0) { | 312 if ((restored_regs & (1 << i)) != 0) { |
309 __ lw(ToRegister(i), MemOperand(at, offset)); | 313 __ ld(ToRegister(i), MemOperand(at, offset)); |
310 } | 314 } |
311 } | 315 } |
312 | 316 |
313 __ InitializeRootRegister(); | 317 __ InitializeRootRegister(); |
314 | 318 |
315 __ pop(at); // Get continuation, leave pc on stack. | 319 __ pop(at); // Get continuation, leave pc on stack. |
316 __ pop(ra); | 320 __ pop(ra); |
317 __ Jump(at); | 321 __ Jump(at); |
318 __ stop("Unreachable."); | 322 __ stop("Unreachable."); |
319 } | 323 } |
320 | 324 |
321 | 325 |
322 // Maximum size of a table entry generated below. | 326 // Maximum size of a table entry generated below. |
323 const int Deoptimizer::table_entry_size_ = 7 * Assembler::kInstrSize; | 327 const int Deoptimizer::table_entry_size_ = 11 * Assembler::kInstrSize; |
324 | 328 |
325 void Deoptimizer::TableEntryGenerator::GeneratePrologue() { | 329 void Deoptimizer::TableEntryGenerator::GeneratePrologue() { |
326 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm()); | 330 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm()); |
327 | 331 |
328 // Create a sequence of deoptimization entries. | 332 // Create a sequence of deoptimization entries. |
329 // Note that registers are still live when jumping to an entry. | 333 // Note that registers are still live when jumping to an entry. |
330 Label table_start; | 334 Label table_start; |
331 __ bind(&table_start); | 335 __ bind(&table_start); |
332 for (int i = 0; i < count(); i++) { | 336 for (int i = 0; i < count(); i++) { |
333 Label start; | 337 Label start; |
334 __ bind(&start); | 338 __ bind(&start); |
335 __ addiu(sp, sp, -1 * kPointerSize); | 339 __ daddiu(sp, sp, -1 * kPointerSize); |
336 // Jump over the remaining deopt entries (including this one). | 340 // Jump over the remaining deopt entries (including this one). |
337 // This code is always reached by calling Jump, which puts the target (label | 341 // This code is always reached by calling Jump, which puts the target (label |
338 // start) into t9. | 342 // start) into t9. |
339 const int remaining_entries = (count() - i) * table_entry_size_; | 343 const int remaining_entries = (count() - i) * table_entry_size_; |
340 __ Addu(t9, t9, remaining_entries); | 344 __ Daddu(t9, t9, remaining_entries); |
341 // 'at' was clobbered so we can only load the current entry value here. | 345 // 'at' was clobbered so we can only load the current entry value here. |
342 __ li(at, i); | 346 __ li(t8, i); |
343 __ jr(t9); // Expose delay slot. | 347 __ jr(t9); // Expose delay slot. |
344 __ sw(at, MemOperand(sp, 0 * kPointerSize)); // In the delay slot. | 348 __ sd(t8, MemOperand(sp, 0 * kPointerSize)); // In the delay slot. |
345 | 349 |
346 // Pad the rest of the code. | 350 // Pad the rest of the code. |
347 while (table_entry_size_ > (masm()->SizeOfCodeGeneratedSince(&start))) { | 351 while (table_entry_size_ > (masm()->SizeOfCodeGeneratedSince(&start))) { |
348 __ nop(); | 352 __ nop(); |
349 } | 353 } |
350 | 354 |
351 ASSERT_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); | 355 ASSERT_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); |
352 } | 356 } |
353 | 357 |
354 ASSERT_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), | 358 ASSERT_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), |
(...skipping 14 matching lines...) Expand all Loading... |
369 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { | 373 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { |
370 // No out-of-line constant pool support. | 374 // No out-of-line constant pool support. |
371 UNREACHABLE(); | 375 UNREACHABLE(); |
372 } | 376 } |
373 | 377 |
374 | 378 |
375 #undef __ | 379 #undef __ |
376 | 380 |
377 | 381 |
378 } } // namespace v8::internal | 382 } } // namespace v8::internal |
OLD | NEW |