Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: src/a64/deoptimizer-a64.cc

Issue 145713002: A64: Implement LOsrEntry and LUnknownOSRValue (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: rebase Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 ReplaceCodeForRelatedFunctions(function, code); 105 ReplaceCodeForRelatedFunctions(function, code);
106 106
107 if (FLAG_trace_deopt) { 107 if (FLAG_trace_deopt) {
108 PrintF("[forced deoptimization: "); 108 PrintF("[forced deoptimization: ");
109 function->PrintName(); 109 function->PrintName();
110 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function)); 110 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
111 } 111 }
112 } 112 }
113 113
114 114
115 // The back edge bookkeeping code matches the pattern:
116 //
117 // <decrement profiling counter>
118 // .. .. .. .. b.pl ok
119 // .. .. .. .. ldr x16, pc+<interrupt stub address>
120 // .. .. .. .. blr x16
121 // ok-label
122 //
123 // We patch the code to the following form:
124 //
125 // <decrement profiling counter>
126 // .. .. .. .. mov x0, x0 (NOP)
127 // .. .. .. .. ldr x16, pc+<on-stack replacement address>
128 // .. .. .. .. blr x16
115 void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code, 129 void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
116 Address pc_after, 130 Address pc_after,
117 Code* interrupt_code, 131 Code* interrupt_code,
118 Code* replacement_code) { 132 Code* replacement_code) {
119 UNIMPLEMENTED();
120 ASSERT(!InterruptCodeIsPatched(unoptimized_code, 133 ASSERT(!InterruptCodeIsPatched(unoptimized_code,
121 pc_after, 134 pc_after,
122 interrupt_code, 135 interrupt_code,
123 replacement_code)); 136 replacement_code));
137
138 // Turn the jump into a nop.
139 Instruction* jump = Instruction::Cast(pc_after)->preceding(3);
140 PatchingAssembler patcher(jump, 1);
141 patcher.nop(Assembler::INTERRUPT_CODE_NOP);
142
143 // Replace the call address.
144 Instruction* load = Instruction::Cast(pc_after)->preceding(2);
145 Address interrupt_address_pointer =
146 reinterpret_cast<Address>(load) + load->ImmPCOffset();
147 Memory::uint64_at(interrupt_address_pointer) =
148 reinterpret_cast<uint64_t>(replacement_code->entry());
149
150 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
151 unoptimized_code, pc_after - 2 * kInstructionSize, replacement_code);
124 } 152 }
125 153
126 154
127 void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code, 155 void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
128 Address pc_after, 156 Address pc_after,
129 Code* interrupt_code, 157 Code* interrupt_code,
130 Code* replacement_code) { 158 Code* replacement_code) {
131 UNIMPLEMENTED();
132 ASSERT(InterruptCodeIsPatched(unoptimized_code, 159 ASSERT(InterruptCodeIsPatched(unoptimized_code,
133 pc_after, 160 pc_after,
134 interrupt_code, 161 interrupt_code,
135 replacement_code)); 162 replacement_code));
163
164 // Turn the nop into a jump.
165 Instruction* jump = Instruction::Cast(pc_after)->preceding(3);
166 PatchingAssembler patcher(jump, 1);
167 patcher.b(4 * kInstructionSize); // ok-label is 4 instructions later.
168
169 // Replace the call address.
170 Instruction* load = Instruction::Cast(pc_after)->preceding(2);
171 Address interrupt_address_pointer =
172 reinterpret_cast<Address>(load) + load->ImmPCOffset();
173 Memory::uint64_at(interrupt_address_pointer) =
174 reinterpret_cast<uint64_t>(interrupt_code->entry());
175
176 interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
177 unoptimized_code, pc_after - 2 * kInstructionSize, interrupt_code);
136 } 178 }
137 179
138 180
139 #ifdef DEBUG 181 #ifdef DEBUG
140 bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code, 182 bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
141 Address pc_after, 183 Address pc_after,
142 Code* interrupt_code, 184 Code* interrupt_code,
143 Code* replacement_code) { 185 Code* replacement_code) {
144 UNIMPLEMENTED(); 186 Instruction* jump_or_nop = Instruction::Cast(pc_after)->preceding(3);
145 return false; 187 return jump_or_nop->IsNop(Assembler::INTERRUPT_CODE_NOP);
146 } 188 }
147 #endif 189 #endif
148 190
149 191
150 void Deoptimizer::DoComputeOsrOutputFrame() { 192 static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
151 UNIMPLEMENTED(); 193 ByteArray* translations = data->TranslationByteArray();
194 int length = data->DeoptCount();
195 for (int i = 0; i < length; i++) {
196 if (data->AstId(i) == ast_id) {
197 TranslationIterator it(translations, data->TranslationIndex(i)->value());
198 int value = it.Next();
199 ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
200 // Read the number of frames.
201 value = it.Next();
202 if (value == 1) return i;
203 }
204 }
205 UNREACHABLE();
206 return -1;
152 } 207 }
153 208
154 209
210 void Deoptimizer::DoComputeOsrOutputFrame() {
211 DeoptimizationInputData* data = DeoptimizationInputData::cast(
212 compiled_code_->deoptimization_data());
213 unsigned ast_id = data->OsrAstId()->value();
214
215 int bailout_id = LookupBailoutId(data, BailoutId(ast_id));
216 unsigned translation_index = data->TranslationIndex(bailout_id)->value();
217 ByteArray* translations = data->TranslationByteArray();
218
219 TranslationIterator iterator(translations, translation_index);
220 Translation::Opcode opcode =
221 static_cast<Translation::Opcode>(iterator.Next());
222 ASSERT(Translation::BEGIN == opcode);
223 USE(opcode);
224 int count = iterator.Next();
225 iterator.Skip(1); // Drop JS frame count.
226 ASSERT(count == 1);
227 USE(count);
228
229 opcode = static_cast<Translation::Opcode>(iterator.Next());
230 USE(opcode);
231 ASSERT(Translation::JS_FRAME == opcode);
232 unsigned node_id = iterator.Next();
233 USE(node_id);
234 ASSERT(node_id == ast_id);
235 int closure_id = iterator.Next();
236 USE(closure_id);
237 ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
238 unsigned height = iterator.Next();
239 unsigned height_in_bytes = height * kPointerSize;
240 USE(height_in_bytes);
241
242 unsigned fixed_size = ComputeFixedSize(function_);
243 unsigned input_frame_size = input_->GetFrameSize();
244 ASSERT(fixed_size + height_in_bytes == input_frame_size);
245
246 unsigned stack_slot_size = compiled_code_->stack_slots() * kPointerSize;
247 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
248 unsigned outgoing_size = outgoing_height * kPointerSize;
249 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
250 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call.
251
252 if (FLAG_trace_osr) {
253 PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
254 reinterpret_cast<intptr_t>(function_));
255 PrintFunctionName();
256 PrintF(" => node=%u, frame=%d->%d]\n",
257 ast_id,
258 input_frame_size,
259 output_frame_size);
260 }
261
262 // There's only one output frame in the OSR case.
263 output_count_ = 1;
264 output_ = new FrameDescription*[1];
265 output_[0] = new(output_frame_size) FrameDescription(
266 output_frame_size, function_);
267 output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
268
269 // Clear the incoming parameters in the optimized frame to avoid
270 // confusing the garbage collector.
271 unsigned output_offset = output_frame_size - kPointerSize;
272 int parameter_count = function_->shared()->formal_parameter_count() + 1;
273 for (int i = 0; i < parameter_count; ++i) {
274 output_[0]->SetFrameSlot(output_offset, 0);
275 output_offset -= kPointerSize;
276 }
277
278 // Translate the incoming parameters. This may overwrite some of the
279 // incoming argument slots we've just cleared.
280 int input_offset = input_frame_size - kPointerSize;
281 bool ok = true;
282 int limit = input_offset - (parameter_count * kPointerSize);
283 while (ok && input_offset > limit) {
284 ok = DoOsrTranslateCommand(&iterator, &input_offset);
285 }
286
287 // There are no translation commands for the caller's pc and fp, the
288 // context, and the function. Set them up explicitly.
289 for (int i = StandardFrameConstants::kCallerPCOffset;
290 ok && i >= StandardFrameConstants::kMarkerOffset;
291 i -= kPointerSize) {
292 uint32_t input_value = input_->GetFrameSlot(input_offset);
293 if (FLAG_trace_osr) {
294 const char* name = "UNKNOWN";
295 switch (i) {
296 case StandardFrameConstants::kCallerPCOffset:
297 name = "caller's pc";
298 break;
299 case StandardFrameConstants::kCallerFPOffset:
300 name = "fp";
301 break;
302 case StandardFrameConstants::kContextOffset:
303 name = "context";
304 break;
305 case StandardFrameConstants::kMarkerOffset:
306 name = "function";
307 break;
308 }
309 PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
310 output_offset,
311 input_value,
312 input_offset,
313 name);
314 }
315
316 output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
317 input_offset -= kPointerSize;
318 output_offset -= kPointerSize;
319 }
320
321 // Translate the rest of the frame.
322 while (ok && input_offset >= 0) {
323 ok = DoOsrTranslateCommand(&iterator, &input_offset);
324 }
325
326 // If translation of any command failed, continue using the input frame.
327 if (!ok) {
328 delete output_[0];
329 output_[0] = input_;
330 output_[0]->SetPc(reinterpret_cast<uint64_t>(from_));
331 } else {
332 // Set up the frame pointer and the context pointer.
333 output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code()));
334 output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code()));
335
336 unsigned pc_offset = data->OsrPcOffset()->value();
337 uint64_t pc = reinterpret_cast<uint64_t>(
338 compiled_code_->entry() + pc_offset);
339 output_[0]->SetPc(pc);
340 }
341 Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR);
342 output_[0]->SetContinuation(
343 reinterpret_cast<uint64_t>(continuation->entry()));
344
345 if (FLAG_trace_osr) {
346 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
347 ok ? "finished" : "aborted",
348 reinterpret_cast<intptr_t>(function_));
349 PrintFunctionName();
350 PrintF(" => pc=0x%0lx]\n", output_[0]->GetPc());
351 }
352 }
353
354
155 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) { 355 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
156 // Set the register values. The values are not important as there are no 356 // Set the register values. The values are not important as there are no
157 // callee saved registers in JavaScript frames, so all registers are 357 // callee saved registers in JavaScript frames, so all registers are
158 // spilled. Registers fp and sp are set to the correct values though. 358 // spilled. Registers fp and sp are set to the correct values though.
159 for (int i = 0; i < Register::NumRegisters(); i++) { 359 for (int i = 0; i < Register::NumRegisters(); i++) {
160 input_->SetRegister(i, 0); 360 input_->SetRegister(i, 0);
161 } 361 }
162 362
163 // TODO(all): Do we also need to set a value to csp? 363 // TODO(all): Do we also need to set a value to csp?
164 input_->SetRegister(jssp.code(), reinterpret_cast<intptr_t>(frame->sp())); 364 input_->SetRegister(jssp.code(), reinterpret_cast<intptr_t>(frame->sp()));
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 // and compute the fp-to-sp delta. 437 // and compute the fp-to-sp delta.
238 Register code_object = x3; 438 Register code_object = x3;
239 Register fp_to_sp = x4; 439 Register fp_to_sp = x4;
240 if ((type() == EAGER) || (type() == SOFT)) { 440 if ((type() == EAGER) || (type() == SOFT)) {
241 __ Mov(code_object, 0); 441 __ Mov(code_object, 0);
242 // Correct one word for bailout id. 442 // Correct one word for bailout id.
243 __ Add(fp_to_sp, 443 __ Add(fp_to_sp,
244 masm()->StackPointer(), 444 masm()->StackPointer(),
245 kSavedRegistersAreaSize + (1 * kPointerSize)); 445 kSavedRegistersAreaSize + (1 * kPointerSize));
246 } else if (type() == OSR) { 446 } else if (type() == OSR) {
247 UNIMPLEMENTED(); 447 __ Mov(code_object, lr);
448 // Correct one word for bailout id.
449 __ Add(fp_to_sp,
450 masm()->StackPointer(),
451 kSavedRegistersAreaSize + (1 * kPointerSize));
248 } else { 452 } else {
249 __ Mov(code_object, lr); 453 __ Mov(code_object, lr);
250 // Correct two words for bailout id and return address. 454 // Correct two words for bailout id and return address.
251 __ Add(fp_to_sp, 455 __ Add(fp_to_sp,
252 masm()->StackPointer(), 456 masm()->StackPointer(),
253 kSavedRegistersAreaSize + (2 * kPointerSize)); 457 kSavedRegistersAreaSize + (2 * kPointerSize));
254 } 458 }
255 __ Sub(fp_to_sp, fp, fp_to_sp); 459 __ Sub(fp_to_sp, fp, fp_to_sp);
256 460
257 // Allocate a new deoptimizer object. 461 // Allocate a new deoptimizer object.
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 } 648 }
445 __ Bind(&done); 649 __ Bind(&done);
446 // TODO(all): We need to add some kind of assertion to verify that Tmp0() 650 // TODO(all): We need to add some kind of assertion to verify that Tmp0()
447 // is not clobbered by Push. 651 // is not clobbered by Push.
448 __ Push(masm()->Tmp0()); 652 __ Push(masm()->Tmp0());
449 } 653 }
450 654
451 #undef __ 655 #undef __
452 656
453 } } // namespace v8::internal 657 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698