Home | History | Annotate | Download | only in src
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "codegen.h"
     31 #include "deoptimizer.h"
     32 #include "disasm.h"
     33 #include "full-codegen.h"
     34 #include "global-handles.h"
     35 #include "macro-assembler.h"
     36 #include "prettyprinter.h"
     37 
     38 
     39 namespace v8 {
     40 namespace internal {
     41 
     42 DeoptimizerData::DeoptimizerData() {
     43   eager_deoptimization_entry_code_ = NULL;
     44   lazy_deoptimization_entry_code_ = NULL;
     45   current_ = NULL;
     46   deoptimizing_code_list_ = NULL;
     47 }
     48 
     49 
     50 DeoptimizerData::~DeoptimizerData() {
     51   if (eager_deoptimization_entry_code_ != NULL) {
     52     eager_deoptimization_entry_code_->Free(EXECUTABLE);
     53     eager_deoptimization_entry_code_ = NULL;
     54   }
     55   if (lazy_deoptimization_entry_code_ != NULL) {
     56     lazy_deoptimization_entry_code_->Free(EXECUTABLE);
     57     lazy_deoptimization_entry_code_ = NULL;
     58   }
     59 }
     60 
     61 Deoptimizer* Deoptimizer::New(JSFunction* function,
     62                               BailoutType type,
     63                               unsigned bailout_id,
     64                               Address from,
     65                               int fp_to_sp_delta,
     66                               Isolate* isolate) {
     67   ASSERT(isolate == Isolate::Current());
     68   Deoptimizer* deoptimizer = new Deoptimizer(isolate,
     69                                              function,
     70                                              type,
     71                                              bailout_id,
     72                                              from,
     73                                              fp_to_sp_delta);
     74   ASSERT(isolate->deoptimizer_data()->current_ == NULL);
     75   isolate->deoptimizer_data()->current_ = deoptimizer;
     76   return deoptimizer;
     77 }
     78 
     79 
     80 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
     81   ASSERT(isolate == Isolate::Current());
     82   Deoptimizer* result = isolate->deoptimizer_data()->current_;
     83   ASSERT(result != NULL);
     84   result->DeleteFrameDescriptions();
     85   isolate->deoptimizer_data()->current_ = NULL;
     86   return result;
     87 }
     88 
     89 
     90 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
     91                                                 int count,
     92                                                 BailoutType type) {
     93   TableEntryGenerator generator(masm, type, count);
     94   generator.Generate();
     95 }
     96 
     97 
     98 class DeoptimizingVisitor : public OptimizedFunctionVisitor {
     99  public:
    100   virtual void EnterContext(Context* context) {
    101     if (FLAG_trace_deopt) {
    102       PrintF("[deoptimize context: %" V8PRIxPTR "]\n",
    103              reinterpret_cast<intptr_t>(context));
    104     }
    105   }
    106 
    107   virtual void VisitFunction(JSFunction* function) {
    108     Deoptimizer::DeoptimizeFunction(function);
    109   }
    110 
    111   virtual void LeaveContext(Context* context) {
    112     context->ClearOptimizedFunctions();
    113   }
    114 };
    115 
    116 
    117 void Deoptimizer::DeoptimizeAll() {
    118   AssertNoAllocation no_allocation;
    119 
    120   if (FLAG_trace_deopt) {
    121     PrintF("[deoptimize all contexts]\n");
    122   }
    123 
    124   DeoptimizingVisitor visitor;
    125   VisitAllOptimizedFunctions(&visitor);
    126 }
    127 
    128 
    129 void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
    130   AssertNoAllocation no_allocation;
    131 
    132   DeoptimizingVisitor visitor;
    133   VisitAllOptimizedFunctionsForGlobalObject(object, &visitor);
    134 }
    135 
    136 
    137 void Deoptimizer::VisitAllOptimizedFunctionsForContext(
    138     Context* context, OptimizedFunctionVisitor* visitor) {
    139   AssertNoAllocation no_allocation;
    140 
    141   ASSERT(context->IsGlobalContext());
    142 
    143   visitor->EnterContext(context);
    144   // Run through the list of optimized functions and deoptimize them.
    145   Object* element = context->OptimizedFunctionsListHead();
    146   while (!element->IsUndefined()) {
    147     JSFunction* element_function = JSFunction::cast(element);
    148     // Get the next link before deoptimizing as deoptimizing will clear the
    149     // next link.
    150     element = element_function->next_function_link();
    151     visitor->VisitFunction(element_function);
    152   }
    153   visitor->LeaveContext(context);
    154 }
    155 
    156 
    157 void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
    158     JSObject* object, OptimizedFunctionVisitor* visitor) {
    159   AssertNoAllocation no_allocation;
    160 
    161   if (object->IsJSGlobalProxy()) {
    162     Object* proto = object->GetPrototype();
    163     ASSERT(proto->IsJSGlobalObject());
    164     VisitAllOptimizedFunctionsForContext(
    165         GlobalObject::cast(proto)->global_context(), visitor);
    166   } else if (object->IsGlobalObject()) {
    167     VisitAllOptimizedFunctionsForContext(
    168         GlobalObject::cast(object)->global_context(), visitor);
    169   }
    170 }
    171 
    172 
    173 void Deoptimizer::VisitAllOptimizedFunctions(
    174     OptimizedFunctionVisitor* visitor) {
    175   AssertNoAllocation no_allocation;
    176 
    177   // Run through the list of all global contexts and deoptimize.
    178   Object* global = Isolate::Current()->heap()->global_contexts_list();
    179   while (!global->IsUndefined()) {
    180     VisitAllOptimizedFunctionsForGlobalObject(Context::cast(global)->global(),
    181                                               visitor);
    182     global = Context::cast(global)->get(Context::NEXT_CONTEXT_LINK);
    183   }
    184 }
    185 
    186 
    187 void Deoptimizer::HandleWeakDeoptimizedCode(
    188     v8::Persistent<v8::Value> obj, void* data) {
    189   DeoptimizingCodeListNode* node =
    190       reinterpret_cast<DeoptimizingCodeListNode*>(data);
    191   RemoveDeoptimizingCode(*node->code());
    192 #ifdef DEBUG
    193   node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
    194   while (node != NULL) {
    195     ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
    196     node = node->next();
    197   }
    198 #endif
    199 }
    200 
    201 
    202 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
    203   deoptimizer->DoComputeOutputFrames();
    204 }
    205 
    206 
    207 Deoptimizer::Deoptimizer(Isolate* isolate,
    208                          JSFunction* function,
    209                          BailoutType type,
    210                          unsigned bailout_id,
    211                          Address from,
    212                          int fp_to_sp_delta)
    213     : isolate_(isolate),
    214       function_(function),
    215       bailout_id_(bailout_id),
    216       bailout_type_(type),
    217       from_(from),
    218       fp_to_sp_delta_(fp_to_sp_delta),
    219       output_count_(0),
    220       output_(NULL),
    221       deferred_heap_numbers_(0) {
    222   if (FLAG_trace_deopt && type != OSR) {
    223     PrintF("**** DEOPT: ");
    224     function->PrintName();
    225     PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
    226            bailout_id,
    227            reinterpret_cast<intptr_t>(from),
    228            fp_to_sp_delta - (2 * kPointerSize));
    229   } else if (FLAG_trace_osr && type == OSR) {
    230     PrintF("**** OSR: ");
    231     function->PrintName();
    232     PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
    233            bailout_id,
    234            reinterpret_cast<intptr_t>(from),
    235            fp_to_sp_delta - (2 * kPointerSize));
    236   }
    237   // Find the optimized code.
    238   if (type == EAGER) {
    239     ASSERT(from == NULL);
    240     optimized_code_ = function_->code();
    241   } else if (type == LAZY) {
    242     optimized_code_ = FindDeoptimizingCodeFromAddress(from);
    243     ASSERT(optimized_code_ != NULL);
    244   } else if (type == OSR) {
    245     // The function has already been optimized and we're transitioning
    246     // from the unoptimized shared version to the optimized one in the
    247     // function. The return address (from) points to unoptimized code.
    248     optimized_code_ = function_->code();
    249     ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
    250     ASSERT(!optimized_code_->contains(from));
    251   }
    252   ASSERT(HEAP->allow_allocation(false));
    253   unsigned size = ComputeInputFrameSize();
    254   input_ = new(size) FrameDescription(size, function);
    255 }
    256 
    257 
    258 Deoptimizer::~Deoptimizer() {
    259   ASSERT(input_ == NULL && output_ == NULL);
    260 }
    261 
    262 
    263 void Deoptimizer::DeleteFrameDescriptions() {
    264   delete input_;
    265   for (int i = 0; i < output_count_; ++i) {
    266     if (output_[i] != input_) delete output_[i];
    267   }
    268   delete[] output_;
    269   input_ = NULL;
    270   output_ = NULL;
    271   ASSERT(!HEAP->allow_allocation(true));
    272 }
    273 
    274 
    275 Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
    276   ASSERT(id >= 0);
    277   if (id >= kNumberOfEntries) return NULL;
    278   LargeObjectChunk* base = NULL;
    279   DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
    280   if (type == EAGER) {
    281     if (data->eager_deoptimization_entry_code_ == NULL) {
    282       data->eager_deoptimization_entry_code_ = CreateCode(type);
    283     }
    284     base = data->eager_deoptimization_entry_code_;
    285   } else {
    286     if (data->lazy_deoptimization_entry_code_ == NULL) {
    287       data->lazy_deoptimization_entry_code_ = CreateCode(type);
    288     }
    289     base = data->lazy_deoptimization_entry_code_;
    290   }
    291   return
    292       static_cast<Address>(base->GetStartAddress()) + (id * table_entry_size_);
    293 }
    294 
    295 
    296 int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
    297   LargeObjectChunk* base = NULL;
    298   DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
    299   if (type == EAGER) {
    300     base = data->eager_deoptimization_entry_code_;
    301   } else {
    302     base = data->lazy_deoptimization_entry_code_;
    303   }
    304   if (base == NULL ||
    305       addr < base->GetStartAddress() ||
    306       addr >= base->GetStartAddress() +
    307           (kNumberOfEntries * table_entry_size_)) {
    308     return kNotDeoptimizationEntry;
    309   }
    310   ASSERT_EQ(0,
    311       static_cast<int>(addr - base->GetStartAddress()) % table_entry_size_);
    312   return static_cast<int>(addr - base->GetStartAddress()) / table_entry_size_;
    313 }
    314 
    315 
    316 int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
    317                                unsigned id,
    318                                SharedFunctionInfo* shared) {
    319   // TODO(kasperl): For now, we do a simple linear search for the PC
    320   // offset associated with the given node id. This should probably be
    321   // changed to a binary search.
    322   int length = data->DeoptPoints();
    323   Smi* smi_id = Smi::FromInt(id);
    324   for (int i = 0; i < length; i++) {
    325     if (data->AstId(i) == smi_id) {
    326       return data->PcAndState(i)->value();
    327     }
    328   }
    329   PrintF("[couldn't find pc offset for node=%u]\n", id);
    330   PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
    331   // Print the source code if available.
    332   HeapStringAllocator string_allocator;
    333   StringStream stream(&string_allocator);
    334   shared->SourceCodePrint(&stream, -1);
    335   PrintF("[source:\n%s\n]", *stream.ToCString());
    336 
    337   UNREACHABLE();
    338   return -1;
    339 }
    340 
    341 
    342 int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
    343   int length = 0;
    344   DeoptimizingCodeListNode* node =
    345       isolate->deoptimizer_data()->deoptimizing_code_list_;
    346   while (node != NULL) {
    347     length++;
    348     node = node->next();
    349   }
    350   return length;
    351 }
    352 
    353 
    354 void Deoptimizer::DoComputeOutputFrames() {
    355   if (bailout_type_ == OSR) {
    356     DoComputeOsrOutputFrame();
    357     return;
    358   }
    359 
    360   // Print some helpful diagnostic information.
    361   int64_t start = OS::Ticks();
    362   if (FLAG_trace_deopt) {
    363     PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
    364            (bailout_type_ == LAZY ? " (lazy)" : ""),
    365            reinterpret_cast<intptr_t>(function_));
    366     function_->PrintName();
    367     PrintF(" @%d]\n", bailout_id_);
    368   }
    369 
    370   // Determine basic deoptimization information.  The optimized frame is
    371   // described by the input data.
    372   DeoptimizationInputData* input_data =
    373       DeoptimizationInputData::cast(optimized_code_->deoptimization_data());
    374   unsigned node_id = input_data->AstId(bailout_id_)->value();
    375   ByteArray* translations = input_data->TranslationByteArray();
    376   unsigned translation_index =
    377       input_data->TranslationIndex(bailout_id_)->value();
    378 
    379   // Do the input frame to output frame(s) translation.
    380   TranslationIterator iterator(translations, translation_index);
    381   Translation::Opcode opcode =
    382       static_cast<Translation::Opcode>(iterator.Next());
    383   ASSERT(Translation::BEGIN == opcode);
    384   USE(opcode);
    385   // Read the number of output frames and allocate an array for their
    386   // descriptions.
    387   int count = iterator.Next();
    388   ASSERT(output_ == NULL);
    389   output_ = new FrameDescription*[count];
    390   for (int i = 0; i < count; ++i) {
    391     output_[i] = NULL;
    392   }
    393   output_count_ = count;
    394 
    395   // Translate each output frame.
    396   for (int i = 0; i < count; ++i) {
    397     DoComputeFrame(&iterator, i);
    398   }
    399 
    400   // Print some helpful diagnostic information.
    401   if (FLAG_trace_deopt) {
    402     double ms = static_cast<double>(OS::Ticks() - start) / 1000;
    403     int index = output_count_ - 1;  // Index of the topmost frame.
    404     JSFunction* function = output_[index]->GetFunction();
    405     PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
    406            reinterpret_cast<intptr_t>(function));
    407     function->PrintName();
    408     PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
    409            node_id,
    410            output_[index]->GetPc(),
    411            FullCodeGenerator::State2String(
    412                static_cast<FullCodeGenerator::State>(
    413                    output_[index]->GetState()->value())),
    414            ms);
    415   }
    416 }
    417 
    418 
    419 void Deoptimizer::MaterializeHeapNumbers() {
    420   for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
    421     HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
    422     Handle<Object> num = isolate_->factory()->NewNumber(d.value());
    423     if (FLAG_trace_deopt) {
    424       PrintF("Materializing a new heap number %p [%e] in slot %p\n",
    425              reinterpret_cast<void*>(*num),
    426              d.value(),
    427              d.slot_address());
    428     }
    429 
    430     Memory::Object_at(d.slot_address()) = *num;
    431   }
    432 }
    433 
    434 
    435 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
    436                                      int frame_index,
    437                                      unsigned output_offset) {
    438   disasm::NameConverter converter;
    439   // A GC-safe temporary placeholder that we can put in the output frame.
    440   const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
    441 
    442   // Ignore commands marked as duplicate and act on the first non-duplicate.
    443   Translation::Opcode opcode =
    444       static_cast<Translation::Opcode>(iterator->Next());
    445   while (opcode == Translation::DUPLICATE) {
    446     opcode = static_cast<Translation::Opcode>(iterator->Next());
    447     iterator->Skip(Translation::NumberOfOperandsFor(opcode));
    448     opcode = static_cast<Translation::Opcode>(iterator->Next());
    449   }
    450 
    451   switch (opcode) {
    452     case Translation::BEGIN:
    453     case Translation::FRAME:
    454     case Translation::DUPLICATE:
    455       UNREACHABLE();
    456       return;
    457 
    458     case Translation::REGISTER: {
    459       int input_reg = iterator->Next();
    460       intptr_t input_value = input_->GetRegister(input_reg);
    461       if (FLAG_trace_deopt) {
    462         PrintF(
    463             "    0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s\n",
    464             output_[frame_index]->GetTop() + output_offset,
    465             output_offset,
    466             input_value,
    467             converter.NameOfCPURegister(input_reg));
    468       }
    469       output_[frame_index]->SetFrameSlot(output_offset, input_value);
    470       return;
    471     }
    472 
    473     case Translation::INT32_REGISTER: {
    474       int input_reg = iterator->Next();
    475       intptr_t value = input_->GetRegister(input_reg);
    476       bool is_smi = Smi::IsValid(value);
    477       if (FLAG_trace_deopt) {
    478         PrintF(
    479             "    0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
    480             output_[frame_index]->GetTop() + output_offset,
    481             output_offset,
    482             value,
    483             converter.NameOfCPURegister(input_reg),
    484             is_smi ? "smi" : "heap number");
    485       }
    486       if (is_smi) {
    487         intptr_t tagged_value =
    488             reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
    489         output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
    490       } else {
    491         // We save the untagged value on the side and store a GC-safe
    492         // temporary placeholder in the frame.
    493         AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
    494                        static_cast<double>(static_cast<int32_t>(value)));
    495         output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
    496       }
    497       return;
    498     }
    499 
    500     case Translation::DOUBLE_REGISTER: {
    501       int input_reg = iterator->Next();
    502       double value = input_->GetDoubleRegister(input_reg);
    503       if (FLAG_trace_deopt) {
    504         PrintF("    0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
    505                output_[frame_index]->GetTop() + output_offset,
    506                output_offset,
    507                value,
    508                DoubleRegister::AllocationIndexToString(input_reg));
    509       }
    510       // We save the untagged value on the side and store a GC-safe
    511       // temporary placeholder in the frame.
    512       AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
    513       output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
    514       return;
    515     }
    516 
    517     case Translation::STACK_SLOT: {
    518       int input_slot_index = iterator->Next();
    519       unsigned input_offset =
    520           input_->GetOffsetFromSlotIndex(this, input_slot_index);
    521       intptr_t input_value = input_->GetFrameSlot(input_offset);
    522       if (FLAG_trace_deopt) {
    523         PrintF("    0x%08" V8PRIxPTR ": ",
    524                output_[frame_index]->GetTop() + output_offset);
    525         PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d]\n",
    526                output_offset,
    527                input_value,
    528                input_offset);
    529       }
    530       output_[frame_index]->SetFrameSlot(output_offset, input_value);
    531       return;
    532     }
    533 
    534     case Translation::INT32_STACK_SLOT: {
    535       int input_slot_index = iterator->Next();
    536       unsigned input_offset =
    537           input_->GetOffsetFromSlotIndex(this, input_slot_index);
    538       intptr_t value = input_->GetFrameSlot(input_offset);
    539       bool is_smi = Smi::IsValid(value);
    540       if (FLAG_trace_deopt) {
    541         PrintF("    0x%08" V8PRIxPTR ": ",
    542                output_[frame_index]->GetTop() + output_offset);
    543         PrintF("[top + %d] <- %" V8PRIdPTR " ; [esp + %d] (%s)\n",
    544                output_offset,
    545                value,
    546                input_offset,
    547                is_smi ? "smi" : "heap number");
    548       }
    549       if (is_smi) {
    550         intptr_t tagged_value =
    551             reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
    552         output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
    553       } else {
    554         // We save the untagged value on the side and store a GC-safe
    555         // temporary placeholder in the frame.
    556         AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
    557                        static_cast<double>(static_cast<int32_t>(value)));
    558         output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
    559       }
    560       return;
    561     }
    562 
    563     case Translation::DOUBLE_STACK_SLOT: {
    564       int input_slot_index = iterator->Next();
    565       unsigned input_offset =
    566           input_->GetOffsetFromSlotIndex(this, input_slot_index);
    567       double value = input_->GetDoubleFrameSlot(input_offset);
    568       if (FLAG_trace_deopt) {
    569         PrintF("    0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
    570                output_[frame_index]->GetTop() + output_offset,
    571                output_offset,
    572                value,
    573                input_offset);
    574       }
    575       // We save the untagged value on the side and store a GC-safe
    576       // temporary placeholder in the frame.
    577       AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
    578       output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
    579       return;
    580     }
    581 
    582     case Translation::LITERAL: {
    583       Object* literal = ComputeLiteral(iterator->Next());
    584       if (FLAG_trace_deopt) {
    585         PrintF("    0x%08" V8PRIxPTR ": [top + %d] <- ",
    586                output_[frame_index]->GetTop() + output_offset,
    587                output_offset);
    588         literal->ShortPrint();
    589         PrintF(" ; literal\n");
    590       }
    591       intptr_t value = reinterpret_cast<intptr_t>(literal);
    592       output_[frame_index]->SetFrameSlot(output_offset, value);
    593       return;
    594     }
    595 
    596     case Translation::ARGUMENTS_OBJECT: {
    597       // Use the arguments marker value as a sentinel and fill in the arguments
    598       // object after the deoptimized frame is built.
    599       ASSERT(frame_index == 0);  // Only supported for first frame.
    600       if (FLAG_trace_deopt) {
    601         PrintF("    0x%08" V8PRIxPTR ": [top + %d] <- ",
    602                output_[frame_index]->GetTop() + output_offset,
    603                output_offset);
    604         isolate_->heap()->arguments_marker()->ShortPrint();
    605         PrintF(" ; arguments object\n");
    606       }
    607       intptr_t value = reinterpret_cast<intptr_t>(
    608           isolate_->heap()->arguments_marker());
    609       output_[frame_index]->SetFrameSlot(output_offset, value);
    610       return;
    611     }
    612   }
    613 }
    614 
    615 
    616 bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
    617                                         int* input_offset) {
    618   disasm::NameConverter converter;
    619   FrameDescription* output = output_[0];
    620 
    621   // The input values are all part of the unoptimized frame so they
    622   // are all tagged pointers.
    623   uintptr_t input_value = input_->GetFrameSlot(*input_offset);
    624   Object* input_object = reinterpret_cast<Object*>(input_value);
    625 
    626   Translation::Opcode opcode =
    627       static_cast<Translation::Opcode>(iterator->Next());
    628   bool duplicate = (opcode == Translation::DUPLICATE);
    629   if (duplicate) {
    630     opcode = static_cast<Translation::Opcode>(iterator->Next());
    631   }
    632 
    633   switch (opcode) {
    634     case Translation::BEGIN:
    635     case Translation::FRAME:
    636     case Translation::DUPLICATE:
    637       UNREACHABLE();  // Malformed input.
    638        return false;
    639 
    640      case Translation::REGISTER: {
    641        int output_reg = iterator->Next();
    642        if (FLAG_trace_osr) {
    643          PrintF("    %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
    644                 converter.NameOfCPURegister(output_reg),
    645                 input_value,
    646                 *input_offset);
    647        }
    648        output->SetRegister(output_reg, input_value);
    649        break;
    650      }
    651 
    652     case Translation::INT32_REGISTER: {
    653       // Abort OSR if we don't have a number.
    654       if (!input_object->IsNumber()) return false;
    655 
    656       int output_reg = iterator->Next();
    657       int int32_value = input_object->IsSmi()
    658           ? Smi::cast(input_object)->value()
    659           : FastD2I(input_object->Number());
    660       // Abort the translation if the conversion lost information.
    661       if (!input_object->IsSmi() &&
    662           FastI2D(int32_value) != input_object->Number()) {
    663         if (FLAG_trace_osr) {
    664           PrintF("**** %g could not be converted to int32 ****\n",
    665                  input_object->Number());
    666         }
    667         return false;
    668       }
    669       if (FLAG_trace_osr) {
    670         PrintF("    %s <- %d (int32) ; [sp + %d]\n",
    671                converter.NameOfCPURegister(output_reg),
    672                int32_value,
    673                *input_offset);
    674       }
    675       output->SetRegister(output_reg, int32_value);
    676       break;
    677     }
    678 
    679     case Translation::DOUBLE_REGISTER: {
    680       // Abort OSR if we don't have a number.
    681       if (!input_object->IsNumber()) return false;
    682 
    683       int output_reg = iterator->Next();
    684       double double_value = input_object->Number();
    685       if (FLAG_trace_osr) {
    686         PrintF("    %s <- %g (double) ; [sp + %d]\n",
    687                DoubleRegister::AllocationIndexToString(output_reg),
    688                double_value,
    689                *input_offset);
    690       }
    691       output->SetDoubleRegister(output_reg, double_value);
    692       break;
    693     }
    694 
    695     case Translation::STACK_SLOT: {
    696       int output_index = iterator->Next();
    697       unsigned output_offset =
    698           output->GetOffsetFromSlotIndex(this, output_index);
    699       if (FLAG_trace_osr) {
    700         PrintF("    [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
    701                output_offset,
    702                input_value,
    703                *input_offset);
    704       }
    705       output->SetFrameSlot(output_offset, input_value);
    706       break;
    707     }
    708 
    709     case Translation::INT32_STACK_SLOT: {
    710       // Abort OSR if we don't have a number.
    711       if (!input_object->IsNumber()) return false;
    712 
    713       int output_index = iterator->Next();
    714       unsigned output_offset =
    715           output->GetOffsetFromSlotIndex(this, output_index);
    716       int int32_value = input_object->IsSmi()
    717           ? Smi::cast(input_object)->value()
    718           : DoubleToInt32(input_object->Number());
    719       // Abort the translation if the conversion lost information.
    720       if (!input_object->IsSmi() &&
    721           FastI2D(int32_value) != input_object->Number()) {
    722         if (FLAG_trace_osr) {
    723           PrintF("**** %g could not be converted to int32 ****\n",
    724                  input_object->Number());
    725         }
    726         return false;
    727       }
    728       if (FLAG_trace_osr) {
    729         PrintF("    [sp + %d] <- %d (int32) ; [sp + %d]\n",
    730                output_offset,
    731                int32_value,
    732                *input_offset);
    733       }
    734       output->SetFrameSlot(output_offset, int32_value);
    735       break;
    736     }
    737 
    738     case Translation::DOUBLE_STACK_SLOT: {
    739       static const int kLowerOffset = 0 * kPointerSize;
    740       static const int kUpperOffset = 1 * kPointerSize;
    741 
    742       // Abort OSR if we don't have a number.
    743       if (!input_object->IsNumber()) return false;
    744 
    745       int output_index = iterator->Next();
    746       unsigned output_offset =
    747           output->GetOffsetFromSlotIndex(this, output_index);
    748       double double_value = input_object->Number();
    749       uint64_t int_value = BitCast<uint64_t, double>(double_value);
    750       int32_t lower = static_cast<int32_t>(int_value);
    751       int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
    752       if (FLAG_trace_osr) {
    753         PrintF("    [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
    754                output_offset + kUpperOffset,
    755                upper,
    756                double_value,
    757                *input_offset);
    758         PrintF("    [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
    759                output_offset + kLowerOffset,
    760                lower,
    761                double_value,
    762                *input_offset);
    763       }
    764       output->SetFrameSlot(output_offset + kLowerOffset, lower);
    765       output->SetFrameSlot(output_offset + kUpperOffset, upper);
    766       break;
    767     }
    768 
    769     case Translation::LITERAL: {
    770       // Just ignore non-materialized literals.
    771       iterator->Next();
    772       break;
    773     }
    774 
    775     case Translation::ARGUMENTS_OBJECT: {
    776       // Optimized code assumes that the argument object has not been
    777       // materialized and so bypasses it when doing arguments access.
    778       // We should have bailed out before starting the frame
    779       // translation.
    780       UNREACHABLE();
    781       return false;
    782     }
    783   }
    784 
    785   if (!duplicate) *input_offset -= kPointerSize;
    786   return true;
    787 }
    788 
    789 
    790 void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
    791                                       Code* check_code,
    792                                       Code* replacement_code) {
    793   // Iterate over the stack check table and patch every stack check
    794   // call to an unconditional call to the replacement code.
    795   ASSERT(unoptimized_code->kind() == Code::FUNCTION);
    796   Address stack_check_cursor = unoptimized_code->instruction_start() +
    797       unoptimized_code->stack_check_table_offset();
    798   uint32_t table_length = Memory::uint32_at(stack_check_cursor);
    799   stack_check_cursor += kIntSize;
    800   for (uint32_t i = 0; i < table_length; ++i) {
    801     uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
    802     Address pc_after = unoptimized_code->instruction_start() + pc_offset;
    803     PatchStackCheckCodeAt(pc_after, check_code, replacement_code);
    804     stack_check_cursor += 2 * kIntSize;
    805   }
    806 }
    807 
    808 
    809 void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
    810                                        Code* check_code,
    811                                        Code* replacement_code) {
    812   // Iterate over the stack check table and revert the patched
    813   // stack check calls.
    814   ASSERT(unoptimized_code->kind() == Code::FUNCTION);
    815   Address stack_check_cursor = unoptimized_code->instruction_start() +
    816       unoptimized_code->stack_check_table_offset();
    817   uint32_t table_length = Memory::uint32_at(stack_check_cursor);
    818   stack_check_cursor += kIntSize;
    819   for (uint32_t i = 0; i < table_length; ++i) {
    820     uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
    821     Address pc_after = unoptimized_code->instruction_start() + pc_offset;
    822     RevertStackCheckCodeAt(pc_after, check_code, replacement_code);
    823     stack_check_cursor += 2 * kIntSize;
    824   }
    825 }
    826 
    827 
    828 unsigned Deoptimizer::ComputeInputFrameSize() const {
    829   unsigned fixed_size = ComputeFixedSize(function_);
    830   // The fp-to-sp delta already takes the context and the function
    831   // into account so we have to avoid double counting them (-2).
    832   unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
    833 #ifdef DEBUG
    834   if (bailout_type_ == OSR) {
    835     // TODO(kasperl): It would be nice if we could verify that the
    836     // size matches with the stack height we can compute based on the
    837     // environment at the OSR entry. The code for that his built into
    838     // the DoComputeOsrOutputFrame function for now.
    839   } else {
    840     unsigned stack_slots = optimized_code_->stack_slots();
    841     unsigned outgoing_size = ComputeOutgoingArgumentSize();
    842     ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
    843   }
    844 #endif
    845   return result;
    846 }
    847 
    848 
    849 unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
    850   // The fixed part of the frame consists of the return address, frame
    851   // pointer, function, context, and all the incoming arguments.
    852   static const unsigned kFixedSlotSize = 4 * kPointerSize;
    853   return ComputeIncomingArgumentSize(function) + kFixedSlotSize;
    854 }
    855 
    856 
    857 unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
    858   // The incoming arguments is the values for formal parameters and
    859   // the receiver. Every slot contains a pointer.
    860   unsigned arguments = function->shared()->formal_parameter_count() + 1;
    861   return arguments * kPointerSize;
    862 }
    863 
    864 
    865 unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
    866   DeoptimizationInputData* data = DeoptimizationInputData::cast(
    867       optimized_code_->deoptimization_data());
    868   unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
    869   return height * kPointerSize;
    870 }
    871 
    872 
    873 Object* Deoptimizer::ComputeLiteral(int index) const {
    874   DeoptimizationInputData* data = DeoptimizationInputData::cast(
    875       optimized_code_->deoptimization_data());
    876   FixedArray* literals = data->LiteralArray();
    877   return literals->get(index);
    878 }
    879 
    880 
    881 void Deoptimizer::AddDoubleValue(intptr_t slot_address,
    882                                  double value) {
    883   HeapNumberMaterializationDescriptor value_desc(
    884       reinterpret_cast<Address>(slot_address), value);
    885   deferred_heap_numbers_.Add(value_desc);
    886 }
    887 
    888 
    889 LargeObjectChunk* Deoptimizer::CreateCode(BailoutType type) {
    890   // We cannot run this if the serializer is enabled because this will
    891   // cause us to emit relocation information for the external
    892   // references. This is fine because the deoptimizer's code section
    893   // isn't meant to be serialized at all.
    894   ASSERT(!Serializer::enabled());
    895 
    896   MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
    897   masm.set_emit_debug_code(false);
    898   GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
    899   CodeDesc desc;
    900   masm.GetCode(&desc);
    901   ASSERT(desc.reloc_size == 0);
    902 
    903   LargeObjectChunk* chunk = LargeObjectChunk::New(desc.instr_size, EXECUTABLE);
    904   memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size);
    905   CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size);
    906   return chunk;
    907 }
    908 
    909 
    910 Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
    911   DeoptimizingCodeListNode* node =
    912       Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
    913   while (node != NULL) {
    914     if (node->code()->contains(addr)) return *node->code();
    915     node = node->next();
    916   }
    917   return NULL;
    918 }
    919 
    920 
    921 void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
    922   DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
    923   ASSERT(data->deoptimizing_code_list_ != NULL);
    924   // Run through the code objects to find this one and remove it.
    925   DeoptimizingCodeListNode* prev = NULL;
    926   DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
    927   while (current != NULL) {
    928     if (*current->code() == code) {
    929       // Unlink from list. If prev is NULL we are looking at the first element.
    930       if (prev == NULL) {
    931         data->deoptimizing_code_list_ = current->next();
    932       } else {
    933         prev->set_next(current->next());
    934       }
    935       delete current;
    936       return;
    937     }
    938     // Move to next in list.
    939     prev = current;
    940     current = current->next();
    941   }
    942   // Deoptimizing code is removed through weak callback. Each object is expected
    943   // to be removed once and only once.
    944   UNREACHABLE();
    945 }
    946 
    947 
    948 FrameDescription::FrameDescription(uint32_t frame_size,
    949                                    JSFunction* function)
    950     : frame_size_(frame_size),
    951       function_(function),
    952       top_(kZapUint32),
    953       pc_(kZapUint32),
    954       fp_(kZapUint32) {
    955   // Zap all the registers.
    956   for (int r = 0; r < Register::kNumRegisters; r++) {
    957     SetRegister(r, kZapUint32);
    958   }
    959 
    960   // Zap all the slots.
    961   for (unsigned o = 0; o < frame_size; o += kPointerSize) {
    962     SetFrameSlot(o, kZapUint32);
    963   }
    964 }
    965 
    966 
    967 unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer,
    968                                                   int slot_index) {
    969   if (slot_index >= 0) {
    970     // Local or spill slots. Skip the fixed part of the frame
    971     // including all arguments.
    972     unsigned base = static_cast<unsigned>(
    973         GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()));
    974     return base - ((slot_index + 1) * kPointerSize);
    975   } else {
    976     // Incoming parameter.
    977     unsigned base = static_cast<unsigned>(GetFrameSize() -
    978         deoptimizer->ComputeIncomingArgumentSize(GetFunction()));
    979     return base - ((slot_index + 1) * kPointerSize);
    980   }
    981 }
    982 
    983 
    984 void TranslationBuffer::Add(int32_t value) {
    985   // Encode the sign bit in the least significant bit.
    986   bool is_negative = (value < 0);
    987   uint32_t bits = ((is_negative ? -value : value) << 1) |
    988       static_cast<int32_t>(is_negative);
    989   // Encode the individual bytes using the least significant bit of
    990   // each byte to indicate whether or not more bytes follow.
    991   do {
    992     uint32_t next = bits >> 7;
    993     contents_.Add(((bits << 1) & 0xFF) | (next != 0));
    994     bits = next;
    995   } while (bits != 0);
    996 }
    997 
    998 
    999 int32_t TranslationIterator::Next() {
   1000   ASSERT(HasNext());
   1001   // Run through the bytes until we reach one with a least significant
   1002   // bit of zero (marks the end).
   1003   uint32_t bits = 0;
   1004   for (int i = 0; true; i += 7) {
   1005     uint8_t next = buffer_->get(index_++);
   1006     bits |= (next >> 1) << i;
   1007     if ((next & 1) == 0) break;
   1008   }
   1009   // The bits encode the sign in the least significant bit.
   1010   bool is_negative = (bits & 1) == 1;
   1011   int32_t result = bits >> 1;
   1012   return is_negative ? -result : result;
   1013 }
   1014 
   1015 
   1016 Handle<ByteArray> TranslationBuffer::CreateByteArray() {
   1017   int length = contents_.length();
   1018   Handle<ByteArray> result =
   1019       Isolate::Current()->factory()->NewByteArray(length, TENURED);
   1020   memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
   1021   return result;
   1022 }
   1023 
   1024 
   1025 void Translation::BeginFrame(int node_id, int literal_id, unsigned height) {
   1026   buffer_->Add(FRAME);
   1027   buffer_->Add(node_id);
   1028   buffer_->Add(literal_id);
   1029   buffer_->Add(height);
   1030 }
   1031 
   1032 
   1033 void Translation::StoreRegister(Register reg) {
   1034   buffer_->Add(REGISTER);
   1035   buffer_->Add(reg.code());
   1036 }
   1037 
   1038 
   1039 void Translation::StoreInt32Register(Register reg) {
   1040   buffer_->Add(INT32_REGISTER);
   1041   buffer_->Add(reg.code());
   1042 }
   1043 
   1044 
   1045 void Translation::StoreDoubleRegister(DoubleRegister reg) {
   1046   buffer_->Add(DOUBLE_REGISTER);
   1047   buffer_->Add(DoubleRegister::ToAllocationIndex(reg));
   1048 }
   1049 
   1050 
   1051 void Translation::StoreStackSlot(int index) {
   1052   buffer_->Add(STACK_SLOT);
   1053   buffer_->Add(index);
   1054 }
   1055 
   1056 
   1057 void Translation::StoreInt32StackSlot(int index) {
   1058   buffer_->Add(INT32_STACK_SLOT);
   1059   buffer_->Add(index);
   1060 }
   1061 
   1062 
   1063 void Translation::StoreDoubleStackSlot(int index) {
   1064   buffer_->Add(DOUBLE_STACK_SLOT);
   1065   buffer_->Add(index);
   1066 }
   1067 
   1068 
   1069 void Translation::StoreLiteral(int literal_id) {
   1070   buffer_->Add(LITERAL);
   1071   buffer_->Add(literal_id);
   1072 }
   1073 
   1074 
   1075 void Translation::StoreArgumentsObject() {
   1076   buffer_->Add(ARGUMENTS_OBJECT);
   1077 }
   1078 
   1079 
   1080 void Translation::MarkDuplicate() {
   1081   buffer_->Add(DUPLICATE);
   1082 }
   1083 
   1084 
   1085 int Translation::NumberOfOperandsFor(Opcode opcode) {
   1086   switch (opcode) {
   1087     case ARGUMENTS_OBJECT:
   1088     case DUPLICATE:
   1089       return 0;
   1090     case BEGIN:
   1091     case REGISTER:
   1092     case INT32_REGISTER:
   1093     case DOUBLE_REGISTER:
   1094     case STACK_SLOT:
   1095     case INT32_STACK_SLOT:
   1096     case DOUBLE_STACK_SLOT:
   1097     case LITERAL:
   1098       return 1;
   1099     case FRAME:
   1100       return 3;
   1101   }
   1102   UNREACHABLE();
   1103   return -1;
   1104 }
   1105 
   1106 
   1107 #ifdef OBJECT_PRINT
   1108 
   1109 const char* Translation::StringFor(Opcode opcode) {
   1110   switch (opcode) {
   1111     case BEGIN:
   1112       return "BEGIN";
   1113     case FRAME:
   1114       return "FRAME";
   1115     case REGISTER:
   1116       return "REGISTER";
   1117     case INT32_REGISTER:
   1118       return "INT32_REGISTER";
   1119     case DOUBLE_REGISTER:
   1120       return "DOUBLE_REGISTER";
   1121     case STACK_SLOT:
   1122       return "STACK_SLOT";
   1123     case INT32_STACK_SLOT:
   1124       return "INT32_STACK_SLOT";
   1125     case DOUBLE_STACK_SLOT:
   1126       return "DOUBLE_STACK_SLOT";
   1127     case LITERAL:
   1128       return "LITERAL";
   1129     case ARGUMENTS_OBJECT:
   1130       return "ARGUMENTS_OBJECT";
   1131     case DUPLICATE:
   1132       return "DUPLICATE";
   1133   }
   1134   UNREACHABLE();
   1135   return "";
   1136 }
   1137 
   1138 #endif
   1139 
   1140 
   1141 DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
   1142   GlobalHandles* global_handles = Isolate::Current()->global_handles();
   1143   // Globalize the code object and make it weak.
   1144   code_ = Handle<Code>::cast(global_handles->Create(code));
   1145   global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
   1146                            this,
   1147                            Deoptimizer::HandleWeakDeoptimizedCode);
   1148 }
   1149 
   1150 
   1151 DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
   1152   GlobalHandles* global_handles = Isolate::Current()->global_handles();
   1153   global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
   1154 }
   1155 
   1156 
   1157 // We can't intermix stack decoding and allocations because
   1158 // deoptimization infrastracture is not GC safe.
   1159 // Thus we build a temporary structure in malloced space.
   1160 SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
   1161                                             DeoptimizationInputData* data,
   1162                                             JavaScriptFrame* frame) {
   1163   Translation::Opcode opcode =
   1164       static_cast<Translation::Opcode>(iterator->Next());
   1165 
   1166   switch (opcode) {
   1167     case Translation::BEGIN:
   1168     case Translation::FRAME:
   1169       // Peeled off before getting here.
   1170       break;
   1171 
   1172     case Translation::ARGUMENTS_OBJECT:
   1173       // This can be only emitted for local slots not for argument slots.
   1174       break;
   1175 
   1176     case Translation::REGISTER:
   1177     case Translation::INT32_REGISTER:
   1178     case Translation::DOUBLE_REGISTER:
   1179     case Translation::DUPLICATE:
   1180       // We are at safepoint which corresponds to call.  All registers are
   1181       // saved by caller so there would be no live registers at this
   1182       // point. Thus these translation commands should not be used.
   1183       break;
   1184 
   1185     case Translation::STACK_SLOT: {
   1186       int slot_index = iterator->Next();
   1187       Address slot_addr = SlotAddress(frame, slot_index);
   1188       return SlotRef(slot_addr, SlotRef::TAGGED);
   1189     }
   1190 
   1191     case Translation::INT32_STACK_SLOT: {
   1192       int slot_index = iterator->Next();
   1193       Address slot_addr = SlotAddress(frame, slot_index);
   1194       return SlotRef(slot_addr, SlotRef::INT32);
   1195     }
   1196 
   1197     case Translation::DOUBLE_STACK_SLOT: {
   1198       int slot_index = iterator->Next();
   1199       Address slot_addr = SlotAddress(frame, slot_index);
   1200       return SlotRef(slot_addr, SlotRef::DOUBLE);
   1201     }
   1202 
   1203     case Translation::LITERAL: {
   1204       int literal_index = iterator->Next();
   1205       return SlotRef(data->LiteralArray()->get(literal_index));
   1206     }
   1207   }
   1208 
   1209   UNREACHABLE();
   1210   return SlotRef();
   1211 }
   1212 
   1213 
   1214 void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame,
   1215                                              int inlined_frame_index,
   1216                                              Vector<SlotRef>* args_slots) {
   1217   AssertNoAllocation no_gc;
   1218   int deopt_index = AstNode::kNoNumber;
   1219   DeoptimizationInputData* data =
   1220       static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
   1221   TranslationIterator it(data->TranslationByteArray(),
   1222                          data->TranslationIndex(deopt_index)->value());
   1223   Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
   1224   ASSERT(opcode == Translation::BEGIN);
   1225   int frame_count = it.Next();
   1226   USE(frame_count);
   1227   ASSERT(frame_count > inlined_frame_index);
   1228   int frames_to_skip = inlined_frame_index;
   1229   while (true) {
   1230     opcode = static_cast<Translation::Opcode>(it.Next());
   1231     // Skip over operands to advance to the next opcode.
   1232     it.Skip(Translation::NumberOfOperandsFor(opcode));
   1233     if (opcode == Translation::FRAME) {
   1234       if (frames_to_skip == 0) {
   1235         // We reached the frame corresponding to the inlined function
   1236         // in question.  Process the translation commands for the
   1237         // arguments.
   1238         //
   1239         // Skip the translation command for the receiver.
   1240         it.Skip(Translation::NumberOfOperandsFor(
   1241             static_cast<Translation::Opcode>(it.Next())));
   1242         // Compute slots for arguments.
   1243         for (int i = 0; i < args_slots->length(); ++i) {
   1244           (*args_slots)[i] = ComputeSlotForNextArgument(&it, data, frame);
   1245         }
   1246         return;
   1247       }
   1248       frames_to_skip--;
   1249     }
   1250   }
   1251 
   1252   UNREACHABLE();
   1253 }
   1254 
   1255 
   1256 } }  // namespace v8::internal
   1257