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 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 // We will patch away the branch so the code is: | 217 // We will patch away the branch so the code is: |
218 // | 218 // |
219 // cmp rsp, <limit> ;; Not changed | 219 // cmp rsp, <limit> ;; Not changed |
220 // nop | 220 // nop |
221 // nop | 221 // nop |
222 // call <on-stack replacment> | 222 // call <on-stack replacment> |
223 // test rax, <loop nesting depth> | 223 // test rax, <loop nesting depth> |
224 // ok: | 224 // ok: |
225 // | 225 // |
226 ASSERT(*(call_target_address - 3) == 0x73 && // jae | 226 ASSERT(*(call_target_address - 3) == 0x73 && // jae |
227 *(call_target_address - 2) == 0x05 && // offset | 227 *(call_target_address - 2) == 0x07 && // offset |
228 *(call_target_address - 1) == 0xe8); // call | 228 *(call_target_address - 1) == 0xe8); // call |
229 *(call_target_address - 3) = 0x90; // nop | 229 *(call_target_address - 3) = 0x90; // nop |
230 *(call_target_address - 2) = 0x90; // nop | 230 *(call_target_address - 2) = 0x90; // nop |
231 Assembler::set_target_address_at(call_target_address, | 231 Assembler::set_target_address_at(call_target_address, |
232 replacement_code->entry()); | 232 replacement_code->entry()); |
233 } | 233 } |
234 | 234 |
235 | 235 |
236 void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, | 236 void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, |
237 Code* check_code, | 237 Code* check_code, |
238 Code* replacement_code) { | 238 Code* replacement_code) { |
239 Address call_target_address = pc_after - kIntSize; | 239 Address call_target_address = pc_after - kIntSize; |
240 ASSERT(replacement_code->entry() == | 240 ASSERT(replacement_code->entry() == |
241 Assembler::target_address_at(call_target_address)); | 241 Assembler::target_address_at(call_target_address)); |
242 // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to | 242 // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to |
243 // restore the conditional branch. | 243 // restore the conditional branch. |
244 ASSERT(*(call_target_address - 3) == 0x90 && // nop | 244 ASSERT(*(call_target_address - 3) == 0x90 && // nop |
245 *(call_target_address - 2) == 0x90 && // nop | 245 *(call_target_address - 2) == 0x90 && // nop |
246 *(call_target_address - 1) == 0xe8); // call | 246 *(call_target_address - 1) == 0xe8); // call |
247 *(call_target_address - 3) = 0x73; // jae | 247 *(call_target_address - 3) = 0x73; // jae |
248 *(call_target_address - 2) = 0x05; // offset | 248 *(call_target_address - 2) = 0x07; // offset |
249 Assembler::set_target_address_at(call_target_address, | 249 Assembler::set_target_address_at(call_target_address, |
250 check_code->entry()); | 250 check_code->entry()); |
251 } | 251 } |
252 | 252 |
253 | 253 |
254 void Deoptimizer::DoComputeOsrOutputFrame() { | 254 static int LookupBailoutId(DeoptimizationInputData* data, unsigned ast_id) { |
255 UNIMPLEMENTED(); | 255 ByteArray* translations = data->TranslationByteArray(); |
| 256 int length = data->DeoptCount(); |
| 257 for (int i = 0; i < length; i++) { |
| 258 if (static_cast<unsigned>(data->AstId(i)->value()) == ast_id) { |
| 259 TranslationIterator it(translations, data->TranslationIndex(i)->value()); |
| 260 int value = it.Next(); |
| 261 ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value)); |
| 262 // Read the number of frames. |
| 263 value = it.Next(); |
| 264 if (value == 1) return i; |
| 265 } |
| 266 } |
| 267 UNREACHABLE(); |
| 268 return -1; |
256 } | 269 } |
257 | 270 |
258 | 271 |
| 272 void Deoptimizer::DoComputeOsrOutputFrame() { |
| 273 DeoptimizationInputData* data = DeoptimizationInputData::cast( |
| 274 optimized_code_->deoptimization_data()); |
| 275 unsigned ast_id = data->OsrAstId()->value(); |
| 276 // TODO(kasperl): This should not be the bailout_id_. It should be |
| 277 // the ast id. Confusing. |
| 278 ASSERT(bailout_id_ == ast_id); |
| 279 |
| 280 int bailout_id = LookupBailoutId(data, ast_id); |
| 281 unsigned translation_index = data->TranslationIndex(bailout_id)->value(); |
| 282 ByteArray* translations = data->TranslationByteArray(); |
| 283 |
| 284 TranslationIterator iterator(translations, translation_index); |
| 285 Translation::Opcode opcode = |
| 286 static_cast<Translation::Opcode>(iterator.Next()); |
| 287 ASSERT(Translation::BEGIN == opcode); |
| 288 USE(opcode); |
| 289 int count = iterator.Next(); |
| 290 ASSERT(count == 1); |
| 291 USE(count); |
| 292 |
| 293 opcode = static_cast<Translation::Opcode>(iterator.Next()); |
| 294 USE(opcode); |
| 295 ASSERT(Translation::FRAME == opcode); |
| 296 unsigned node_id = iterator.Next(); |
| 297 USE(node_id); |
| 298 ASSERT(node_id == ast_id); |
| 299 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next())); |
| 300 USE(function); |
| 301 ASSERT(function == function_); |
| 302 unsigned height = iterator.Next(); |
| 303 unsigned height_in_bytes = height * kPointerSize; |
| 304 USE(height_in_bytes); |
| 305 |
| 306 unsigned fixed_size = ComputeFixedSize(function_); |
| 307 unsigned input_frame_size = input_->GetFrameSize(); |
| 308 ASSERT(fixed_size + height_in_bytes == input_frame_size); |
| 309 |
| 310 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize; |
| 311 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value(); |
| 312 unsigned outgoing_size = outgoing_height * kPointerSize; |
| 313 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size; |
| 314 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call. |
| 315 |
| 316 if (FLAG_trace_osr) { |
| 317 PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ", |
| 318 reinterpret_cast<intptr_t>(function_)); |
| 319 function_->PrintName(); |
| 320 PrintF(" => node=%u, frame=%d->%d]\n", |
| 321 ast_id, |
| 322 input_frame_size, |
| 323 output_frame_size); |
| 324 } |
| 325 |
| 326 // There's only one output frame in the OSR case. |
| 327 output_count_ = 1; |
| 328 output_ = new FrameDescription*[1]; |
| 329 output_[0] = new(output_frame_size) FrameDescription( |
| 330 output_frame_size, function_); |
| 331 |
| 332 // Clear the incoming parameters in the optimized frame to avoid |
| 333 // confusing the garbage collector. |
| 334 unsigned output_offset = output_frame_size - kPointerSize; |
| 335 int parameter_count = function_->shared()->formal_parameter_count() + 1; |
| 336 for (int i = 0; i < parameter_count; ++i) { |
| 337 output_[0]->SetFrameSlot(output_offset, 0); |
| 338 output_offset -= kPointerSize; |
| 339 } |
| 340 |
| 341 // Translate the incoming parameters. This may overwrite some of the |
| 342 // incoming argument slots we've just cleared. |
| 343 int input_offset = input_frame_size - kPointerSize; |
| 344 bool ok = true; |
| 345 int limit = input_offset - (parameter_count * kPointerSize); |
| 346 while (ok && input_offset > limit) { |
| 347 ok = DoOsrTranslateCommand(&iterator, &input_offset); |
| 348 } |
| 349 |
| 350 // There are no translation commands for the caller's pc and fp, the |
| 351 // context, and the function. Set them up explicitly. |
| 352 for (int i = 0; ok && i < 4; i++) { |
| 353 intptr_t input_value = input_->GetFrameSlot(input_offset); |
| 354 if (FLAG_trace_osr) { |
| 355 PrintF(" [esp + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] (fixed part)\n", |
| 356 output_offset, |
| 357 input_value, |
| 358 input_offset); |
| 359 } |
| 360 output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset)); |
| 361 input_offset -= kPointerSize; |
| 362 output_offset -= kPointerSize; |
| 363 } |
| 364 |
| 365 // Translate the rest of the frame. |
| 366 while (ok && input_offset >= 0) { |
| 367 ok = DoOsrTranslateCommand(&iterator, &input_offset); |
| 368 } |
| 369 |
| 370 // If translation of any command failed, continue using the input frame. |
| 371 if (!ok) { |
| 372 delete output_[0]; |
| 373 output_[0] = input_; |
| 374 output_[0]->SetPc(reinterpret_cast<intptr_t>(from_)); |
| 375 } else { |
| 376 // Setup the frame pointer and the context pointer. |
| 377 output_[0]->SetRegister(rbp.code(), input_->GetRegister(rbp.code())); |
| 378 output_[0]->SetRegister(rsi.code(), input_->GetRegister(rsi.code())); |
| 379 |
| 380 unsigned pc_offset = data->OsrPcOffset()->value(); |
| 381 intptr_t pc = reinterpret_cast<intptr_t>( |
| 382 optimized_code_->entry() + pc_offset); |
| 383 output_[0]->SetPc(pc); |
| 384 } |
| 385 Code* continuation = Builtins::builtin(Builtins::NotifyOSR); |
| 386 output_[0]->SetContinuation( |
| 387 reinterpret_cast<intptr_t>(continuation->entry())); |
| 388 |
| 389 if (FLAG_trace_osr) { |
| 390 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ", |
| 391 ok ? "finished" : "aborted", |
| 392 reinterpret_cast<intptr_t>(function)); |
| 393 function->PrintName(); |
| 394 PrintF(" => pc=0x%0" V8PRIxPTR "]\n", output_[0]->GetPc()); |
| 395 } |
| 396 } |
| 397 |
| 398 |
259 void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, | 399 void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, |
260 int frame_index) { | 400 int frame_index) { |
261 // Read the ast node id, function, and frame height for this output frame. | 401 // Read the ast node id, function, and frame height for this output frame. |
262 Translation::Opcode opcode = | 402 Translation::Opcode opcode = |
263 static_cast<Translation::Opcode>(iterator->Next()); | 403 static_cast<Translation::Opcode>(iterator->Next()); |
264 USE(opcode); | 404 USE(opcode); |
265 ASSERT(Translation::FRAME == opcode); | 405 ASSERT(Translation::FRAME == opcode); |
266 int node_id = iterator->Next(); | 406 int node_id = iterator->Next(); |
267 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); | 407 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); |
268 unsigned height = iterator->Next(); | 408 unsigned height = iterator->Next(); |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 } | 772 } |
633 __ bind(&done); | 773 __ bind(&done); |
634 } | 774 } |
635 | 775 |
636 #undef __ | 776 #undef __ |
637 | 777 |
638 | 778 |
639 } } // namespace v8::internal | 779 } } // namespace v8::internal |
640 | 780 |
641 #endif // V8_TARGET_ARCH_X64 | 781 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |