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