| Index: src/deoptimizer.cc
|
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
|
| index d1b00f8bdea718a71eca5d12d47900cd2f677883..aa8c1503a04851393e5d00f9298f0537cbdbd0a6 100644
|
| --- a/src/deoptimizer.cc
|
| +++ b/src/deoptimizer.cc
|
| @@ -99,6 +99,22 @@ Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
|
| ASSERT(isolate == Isolate::Current());
|
| Deoptimizer* result = isolate->deoptimizer_data()->current_;
|
| ASSERT(result != NULL);
|
| + if (isolate->optimized_handler_patch_buffer() != NULL) {
|
| + ASSERT(result->bailout_type_ == LAZY);
|
| + // Before allowing allocation, patch the optimized code back. The
|
| + // patched code has relocation info that does not agree with the code,
|
| + // so the patched code should not be seen by the garbage collector.
|
| + Code* code = result->optimized_code_;
|
| + DeoptimizationInputData* deopt_data =
|
| + DeoptimizationInputData::cast(code->deoptimization_data());
|
| + int deopt_index = isolate->optimized_handler_deopt_index();
|
| + byte* patch_address =
|
| + code->instruction_start() + deopt_data->Pc(deopt_index)->value();
|
| + memcpy(patch_address, isolate->optimized_handler_patch_buffer(),
|
| + patch_size());
|
| + // FIXME(mmassi): why doesn't it clear immediately also the patch buffer?
|
| + isolate->ClearOptimizedHandlerByDeopt(code);
|
| + }
|
| result->DeleteFrameDescriptions();
|
| isolate->deoptimizer_data()->current_ = NULL;
|
| return result;
|
| @@ -140,10 +156,17 @@ DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
|
| int deoptimization_index = safepoint_entry.deoptimization_index();
|
| ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
|
|
|
| + // Find the size of exception handlers.
|
| + DeoptimizationInputData* deoptimization_data =
|
| + DeoptimizationInputData::cast(code->deoptimization_data());
|
| + unsigned handler_count =
|
| + deoptimization_data->HandlerCount(deoptimization_index)->value();
|
| + unsigned handler_size = handler_count * StackHandlerConstants::kSize;
|
| +
|
| // Always use the actual stack slots when calculating the fp to sp
|
| // delta adding two for the function and context.
|
| unsigned stack_slots = code->stack_slots();
|
| - unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
|
| + unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize) + handler_size;
|
|
|
| Deoptimizer* deoptimizer = new Deoptimizer(isolate,
|
| function,
|
| @@ -567,6 +590,13 @@ void Deoptimizer::DoComputeOutputFrames() {
|
| int count = iterator.Next();
|
| iterator.Next(); // Drop JS frames count.
|
| ASSERT(output_ == NULL);
|
| +
|
| + // If this deoptimization is needed to transfer control to a catch clause
|
| + // only the first frame is relevant.
|
| + if (isolate_->optimized_handler_patch_buffer() != NULL) {
|
| + count = 1;
|
| + }
|
| +
|
| output_ = new FrameDescription*[count];
|
| for (int i = 0; i < count; ++i) {
|
| output_[i] = NULL;
|
| @@ -824,7 +854,18 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
| int input_slot_index = iterator->Next();
|
| unsigned input_offset =
|
| input_->GetOffsetFromSlotIndex(input_slot_index);
|
| - intptr_t input_value = input_->GetFrameSlot(input_offset);
|
| + intptr_t input_value;
|
| + if (isolate_->optimized_handler_patch_buffer() != NULL &&
|
| + input_offset >= input_->frame_size()) {
|
| + // Skip stack slots that were above the handler (they must be
|
| + // arguments that must be thrown away because try is a statement).
|
| + input_value = 0;
|
| + if (FLAG_trace_deopt) {
|
| + PrintF(" SKIPPING SLOT ABOVE HANDLER (ARGUMENT)\n");
|
| + }
|
| + } else {
|
| + input_value = input_->GetFrameSlot(input_offset);
|
| + }
|
| if (FLAG_trace_deopt) {
|
| PrintF(" 0x%08" V8PRIxPTR ": ",
|
| output_[frame_index]->GetTop() + output_offset);
|
| @@ -1026,7 +1067,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
|
| case Translation::SETTER_STUB_FRAME:
|
| case Translation::DUPLICATE:
|
| UNREACHABLE(); // Malformed input.
|
| - return false;
|
| + return false;
|
|
|
| case Translation::REGISTER: {
|
| int output_reg = iterator->Next();
|
| @@ -1233,10 +1274,15 @@ void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
|
|
|
|
|
| unsigned Deoptimizer::ComputeInputFrameSize() const {
|
| + // This is the size of the frame that is the same for both optimized and
|
| + // unoptimized frames---the incoming parameters and the fixed part of the
|
| + // frame.
|
| unsigned fixed_size = ComputeFixedSize(function_);
|
| +
|
| // The fp-to-sp delta already takes the context and the function
|
| // into account so we have to avoid double counting them (-2).
|
| unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
|
| +
|
| #ifdef DEBUG
|
| if (bailout_type_ == OSR) {
|
| // TODO(kasperl): It would be nice if we could verify that the
|
| @@ -1244,9 +1290,21 @@ unsigned Deoptimizer::ComputeInputFrameSize() const {
|
| // environment at the OSR entry. The code for that his built into
|
| // the DoComputeOsrOutputFrame function for now.
|
| } else {
|
| - unsigned stack_slots = optimized_code_->stack_slots();
|
| - unsigned outgoing_size = ComputeOutgoingArgumentSize();
|
| - ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
|
| + // Verify the actual frame size matches the expected (fixed part +
|
| + // spill slots + exception handlers + outgoing arguments).
|
| + unsigned spill_slots_size = optimized_code_->stack_slots() * kPointerSize;
|
| + unsigned handlers_size = ComputeHandlersSize();
|
| + // If we are doing lazy deoptimization for catching in an optimized
|
| + // frame, one of the handlers in the frame description has already been
|
| + // dropped by throwing to it.
|
| + if (isolate_->optimized_handler_patch_buffer() != NULL) {
|
| + ASSERT(bailout_type_ == LAZY);
|
| + ASSERT(static_cast<int>(handlers_size) >= StackHandlerConstants::kSize);
|
| + handlers_size -= StackHandlerConstants::kSize;
|
| + }
|
| + unsigned outgoing_arg_size = ComputeOutgoingArgumentSize();
|
| + ASSERT(result ==
|
| + fixed_size + spill_slots_size + handlers_size + outgoing_arg_size);
|
| }
|
| #endif
|
| return result;
|
| @@ -1270,6 +1328,12 @@ unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
|
|
|
|
|
| unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
|
| + // Since try is a statement there will not be arguments left on the stack
|
| + // once we have popped the handler.
|
| + if (isolate_->optimized_handler_patch_buffer() != NULL) {
|
| + return 0;
|
| + }
|
| +
|
| DeoptimizationInputData* data = DeoptimizationInputData::cast(
|
| optimized_code_->deoptimization_data());
|
| unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
|
| @@ -1277,6 +1341,14 @@ unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
|
| }
|
|
|
|
|
| +unsigned Deoptimizer::ComputeHandlersSize() const {
|
| + DeoptimizationInputData* data = DeoptimizationInputData::cast(
|
| + optimized_code_->deoptimization_data());
|
| + unsigned handler_count = data->HandlerCount(bailout_id_)->value();
|
| + return handler_count * StackHandlerConstants::kSize;
|
| +}
|
| +
|
| +
|
| Object* Deoptimizer::ComputeLiteral(int index) const {
|
| DeoptimizationInputData* data = DeoptimizationInputData::cast(
|
| optimized_code_->deoptimization_data());
|
| @@ -1508,11 +1580,13 @@ void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
|
|
|
| void Translation::BeginJSFrame(BailoutId node_id,
|
| int literal_id,
|
| - unsigned height) {
|
| + unsigned height,
|
| + int handler_count) {
|
| buffer_->Add(JS_FRAME, zone());
|
| buffer_->Add(node_id.ToInt(), zone());
|
| buffer_->Add(literal_id, zone());
|
| buffer_->Add(height, zone());
|
| + buffer_->Add(handler_count, zone());
|
| }
|
|
|
|
|
| @@ -1602,7 +1676,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
| case CONSTRUCT_STUB_FRAME:
|
| return 2;
|
| case JS_FRAME:
|
| - return 3;
|
| + return 4;
|
| }
|
| UNREACHABLE();
|
| return -1;
|
|
|