13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// Redistribution and use in source and binary forms, with or without
3b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// modification, are permitted provided that the following conditions are
4b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// met:
5b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//
6b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//     * Redistributions of source code must retain the above copyright
7b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//       notice, this list of conditions and the following disclaimer.
8b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//     * Redistributions in binary form must reproduce the above
9b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//       copyright notice, this list of conditions and the following
10b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//       disclaimer in the documentation and/or other materials provided
11b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//       with the distribution.
12b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//     * Neither the name of Google Inc. nor the names of its
13b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//       contributors may be used to endorse or promote products derived
14b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//       from this software without specific prior written permission.
15b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch//
16b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
28b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "v8.h"
29b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
30b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "codegen.h"
31b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "deoptimizer.h"
32b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "full-codegen.h"
33b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "safepoint-table.h"
34b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
35b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochnamespace v8 {
36b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochnamespace internal {
37b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochconst int Deoptimizer::table_entry_size_ = 16;
39b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockint Deoptimizer::patch_size() {
421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  const int kCallInstructionSizeInWords = 3;
431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return kCallInstructionSizeInWords * Assembler::kInstrSize;
441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
47b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid Deoptimizer::DeoptimizeFunction(JSFunction* function) {
4844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  HandleScope scope;
49b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  AssertNoAllocation no_allocation;
50b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
51b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (!function->IsOptimized()) return;
52b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
53b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the optimized code.
54b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Code* code = function->code();
552b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch  Address code_start_address = code->instruction_start();
56b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
57b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Invalidate the relocation information, as it will become invalid by the
58b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // code patching below, and is not needed any more.
59b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  code->InvalidateRelocation();
60b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
612b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch  // For each LLazyBailout instruction insert a call to the corresponding
622b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch  // deoptimization entry.
632b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch  DeoptimizationInputData* deopt_data =
642b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch      DeoptimizationInputData::cast(code->deoptimization_data());
65b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#ifdef DEBUG
662b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch  Address prev_call_address = NULL;
67b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#endif
682b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
692b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    if (deopt_data->Pc(i)->value() == -1) continue;
702b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    Address call_address = code_start_address + deopt_data->Pc(i)->value();
712b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
722b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
732b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch                                                      RelocInfo::NONE);
742b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
752b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
762b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    ASSERT(call_size_in_bytes <= patch_size());
772b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    CodePatcher patcher(call_address, call_size_in_words);
782b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
792b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    ASSERT(prev_call_address == NULL ||
802b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch           call_address >= prev_call_address + patch_size());
812b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    ASSERT(call_address + patch_size() <= code->instruction_end());
82b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#ifdef DEBUG
832b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch    prev_call_address = call_address;
84b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#endif
852b4ba1175df6a5a6b9b5cda034189197bf6565ecBen Murdoch  }
86b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = code->GetIsolate();
883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
89b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Add the deoptimizing code to the list.
90b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  DeoptimizerData* data = isolate->deoptimizer_data();
9244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  node->set_next(data->deoptimizing_code_list_);
9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  data->deoptimizing_code_list_ = node;
94b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // We might be in the middle of incremental marking with compaction.
963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Tell collector to treat this code object in a special way and
973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ignore all slots that might have been recorded on it.
983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  isolate->heap()->mark_compact_collector()->InvalidateCode(code);
993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set the code for the function to non-optimized version.
101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  function->ReplaceCode(function->shared()->code());
102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_deopt) {
104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("[forced deoptimization: ");
105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    function->PrintName();
106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int32_t kBranchBeforeStackCheck = 0x2a000001;
1123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int32_t kBranchBeforeInterrupt =  0x5a000004;
1133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
1163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                        Address pc_after,
1171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                        Code* check_code,
1181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                        Code* replacement_code) {
119e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  const int kInstrSize = Assembler::kInstrSize;
120e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // The call of the stack guard check has the following form:
121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  e1 5d 00 0c       cmp sp, <limit>
122e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  2a 00 00 01       bcs ok
123e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  e5 9f c? ??       ldr ip, [pc, <stack guard address>]
124e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  e1 2f ff 3c       blx ip
1253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp);
126e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(Assembler::IsLdrPcImmediateOffset(
127e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      Assembler::instr_at(pc_after - 2 * kInstrSize)));
1283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_count_based_interrupts) {
1293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT_EQ(kBranchBeforeInterrupt,
1303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              Memory::int32_at(pc_after - 3 * kInstrSize));
1313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
1323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT_EQ(kBranchBeforeStackCheck,
1333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              Memory::int32_at(pc_after - 3 * kInstrSize));
1343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
135e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
136e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // We patch the code to the following form:
137e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  e1 5d 00 0c       cmp sp, <limit>
138e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  e1 a0 00 00       mov r0, r0 (NOP)
139e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  e5 9f c? ??       ldr ip, [pc, <on-stack replacement address>]
140e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //  e1 2f ff 3c       blx ip
141e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // and overwrite the constant containing the
142e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // address of the stack check stub.
143e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
144e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Replace conditional jump with NOP.
145e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
146e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  patcher.masm()->nop();
147e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
148e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Replace the stack check address in the constant pool
149e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // with the entry address of the replacement code.
150e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  uint32_t stack_check_address_offset = Memory::uint16_at(pc_after -
151e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      2 * kInstrSize) & 0xfff;
152e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Address stack_check_address_pointer = pc_after + stack_check_address_offset;
153e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(Memory::uint32_at(stack_check_address_pointer) ==
154e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch         reinterpret_cast<uint32_t>(check_code->entry()));
155e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Memory::uint32_at(stack_check_address_pointer) =
156e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      reinterpret_cast<uint32_t>(replacement_code->entry());
1573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
1593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      unoptimized_code, pc_after - 2 * kInstrSize, replacement_code);
160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
1643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                         Address pc_after,
1651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         Code* check_code,
1661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         Code* replacement_code) {
167e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  const int kInstrSize = Assembler::kInstrSize;
1683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp);
1693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(Assembler::IsLdrPcImmediateOffset(
1703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      Assembler::instr_at(pc_after - 2 * kInstrSize)));
171e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
172e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Replace NOP with conditional jump.
173e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
1743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_count_based_interrupts) {
1753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    patcher.masm()->b(+16, pl);
1763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT_EQ(kBranchBeforeInterrupt,
1773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              Memory::int32_at(pc_after - 3 * kInstrSize));
1783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
1793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    patcher.masm()->b(+4, cs);
1803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT_EQ(kBranchBeforeStackCheck,
1813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              Memory::int32_at(pc_after - 3 * kInstrSize));
1823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
183e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
184e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Replace the stack check address in the constant pool
185e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // with the entry address of the replacement code.
186e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  uint32_t stack_check_address_offset = Memory::uint16_at(pc_after -
187e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      2 * kInstrSize) & 0xfff;
188e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Address stack_check_address_pointer = pc_after + stack_check_address_offset;
189e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(Memory::uint32_at(stack_check_address_pointer) ==
190e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch         reinterpret_cast<uint32_t>(replacement_code->entry()));
191e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Memory::uint32_at(stack_check_address_pointer) =
192e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      reinterpret_cast<uint32_t>(check_code->entry());
1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
1953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      unoptimized_code, pc_after - 2 * kInstrSize, check_code);
196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockstatic int LookupBailoutId(DeoptimizationInputData* data, unsigned ast_id) {
2001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ByteArray* translations = data->TranslationByteArray();
2011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int length = data->DeoptCount();
2021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < length; i++) {
2031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (static_cast<unsigned>(data->AstId(i)->value()) == ast_id) {
2041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      TranslationIterator it(translations,  data->TranslationIndex(i)->value());
2051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      int value = it.Next();
2061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
2071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Read the number of frames.
2081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      value = it.Next();
2091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      if (value == 1) return i;
2101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
2111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
2121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  UNREACHABLE();
2131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return -1;
2141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
2151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid Deoptimizer::DoComputeOsrOutputFrame() {
2181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  DeoptimizationInputData* data = DeoptimizationInputData::cast(
2191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      optimized_code_->deoptimization_data());
2201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned ast_id = data->OsrAstId()->value();
2211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int bailout_id = LookupBailoutId(data, ast_id);
2231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned translation_index = data->TranslationIndex(bailout_id)->value();
2241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ByteArray* translations = data->TranslationByteArray();
2251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  TranslationIterator iterator(translations, translation_index);
2271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Translation::Opcode opcode =
2281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      static_cast<Translation::Opcode>(iterator.Next());
2291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(Translation::BEGIN == opcode);
2301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  USE(opcode);
2311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int count = iterator.Next();
2323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  iterator.Skip(1);  // Drop JS frame count.
2331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(count == 1);
2341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  USE(count);
2351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  opcode = static_cast<Translation::Opcode>(iterator.Next());
2371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  USE(opcode);
2383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(Translation::JS_FRAME == opcode);
2391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned node_id = iterator.Next();
2401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  USE(node_id);
2411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(node_id == ast_id);
2421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next()));
2431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  USE(function);
2441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(function == function_);
2451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned height = iterator.Next();
2461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned height_in_bytes = height * kPointerSize;
2471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  USE(height_in_bytes);
2481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned fixed_size = ComputeFixedSize(function_);
2501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned input_frame_size = input_->GetFrameSize();
2511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(fixed_size + height_in_bytes == input_frame_size);
2521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize;
2541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
2551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned outgoing_size = outgoing_height * kPointerSize;
2561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
2571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(outgoing_size == 0);  // OSR does not happen in the middle of a call.
2581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (FLAG_trace_osr) {
2601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
2611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block           reinterpret_cast<intptr_t>(function_));
2621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    function_->PrintName();
2631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    PrintF(" => node=%u, frame=%d->%d]\n",
2641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block           ast_id,
2651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block           input_frame_size,
2661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block           output_frame_size);
2671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
2681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // There's only one output frame in the OSR case.
2701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  output_count_ = 1;
2711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  output_ = new FrameDescription*[1];
2721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  output_[0] = new(output_frame_size) FrameDescription(
2731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      output_frame_size, function_);
2743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
2751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Clear the incoming parameters in the optimized frame to avoid
2771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // confusing the garbage collector.
2781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  unsigned output_offset = output_frame_size - kPointerSize;
2791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int parameter_count = function_->shared()->formal_parameter_count() + 1;
2801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < parameter_count; ++i) {
2811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_[0]->SetFrameSlot(output_offset, 0);
2821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_offset -= kPointerSize;
2831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
2841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Translate the incoming parameters. This may overwrite some of the
2861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // incoming argument slots we've just cleared.
2871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int input_offset = input_frame_size - kPointerSize;
2881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  bool ok = true;
2891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int limit = input_offset - (parameter_count * kPointerSize);
2901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  while (ok && input_offset > limit) {
2911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    ok = DoOsrTranslateCommand(&iterator, &input_offset);
2921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
2931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // There are no translation commands for the caller's pc and fp, the
2951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // context, and the function.  Set them up explicitly.
29644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (int i =  StandardFrameConstants::kCallerPCOffset;
29744f0eee88ff00398ff7f715fab053374d808c90dSteve Block       ok && i >=  StandardFrameConstants::kMarkerOffset;
29844f0eee88ff00398ff7f715fab053374d808c90dSteve Block       i -= kPointerSize) {
2991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    uint32_t input_value = input_->GetFrameSlot(input_offset);
3001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (FLAG_trace_osr) {
30144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      const char* name = "UNKNOWN";
30244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      switch (i) {
30344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case StandardFrameConstants::kCallerPCOffset:
30444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          name = "caller's pc";
30544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
30644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case StandardFrameConstants::kCallerFPOffset:
30744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          name = "fp";
30844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
30944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case StandardFrameConstants::kContextOffset:
31044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          name = "context";
31144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
31244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        case StandardFrameConstants::kMarkerOffset:
31344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          name = "function";
31444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          break;
31544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
31644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      PrintF("    [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
3171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block             output_offset,
3181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block             input_value,
31944f0eee88ff00398ff7f715fab053374d808c90dSteve Block             input_offset,
32044f0eee88ff00398ff7f715fab053374d808c90dSteve Block             name);
3211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
32244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
3241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    input_offset -= kPointerSize;
3251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_offset -= kPointerSize;
3261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
3271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Translate the rest of the frame.
3291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  while (ok && input_offset >= 0) {
3301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    ok = DoOsrTranslateCommand(&iterator, &input_offset);
3311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
3321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // If translation of any command failed, continue using the input frame.
3341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (!ok) {
3351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    delete output_[0];
3361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_[0] = input_;
3371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
3381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else {
3393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Set up the frame pointer and the context pointer.
3401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code()));
3411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code()));
3421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    unsigned pc_offset = data->OsrPcOffset()->value();
3441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    uint32_t pc = reinterpret_cast<uint32_t>(
3451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        optimized_code_->entry() + pc_offset);
3461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    output_[0]->SetPc(pc);
3471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
34844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR);
3491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  output_[0]->SetContinuation(
3501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      reinterpret_cast<uint32_t>(continuation->entry()));
3511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (FLAG_trace_osr) {
3531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
3541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block           ok ? "finished" : "aborted",
3551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block           reinterpret_cast<intptr_t>(function));
3561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    function->PrintName();
3571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
3581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
3633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                 int frame_index) {
3643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
3653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned height = iterator->Next();
3663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned height_in_bytes = height * kPointerSize;
3673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("  translating arguments adaptor => height=%d\n", height_in_bytes);
3693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned output_frame_size = height_in_bytes + fixed_frame_size;
3733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate and store the output frame description.
3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  FrameDescription* output_frame =
3763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      new(output_frame_size) FrameDescription(output_frame_size, function);
3773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
3783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Arguments adaptor can not be topmost or bottommost.
3803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
3813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(output_[frame_index] == NULL);
3823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_[frame_index] = output_frame;
3833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The top address of the frame is computed from the previous
3853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // frame's top and this frame's size.
3863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  uint32_t top_address;
3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetTop(top_address);
3893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Compute the incoming parameter translation.
3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int parameter_count = height;
3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned output_offset = output_frame_size;
3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < parameter_count; ++i) {
3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    output_offset -= kPointerSize;
3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    DoTranslateCommand(iterator, frame_index, output_offset);
3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Read caller's PC from the previous frame.
3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  intptr_t callers_pc = output_[frame_index - 1]->GetPc();
4013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, callers_pc);
4023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, callers_pc);
4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Read caller's FP from the previous frame, and set this frame's FP.
4083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
4093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  intptr_t value = output_[frame_index - 1]->GetFp();
4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
4113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  intptr_t fp_value = top_address + output_offset;
4123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFp(fp_value);
4133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
4143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
4153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           fp_value, output_offset, value);
4163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // A marker value is used in place of the context.
4193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  intptr_t context = reinterpret_cast<intptr_t>(
4213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
4223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, context);
4233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
4243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; context (adaptor sentinel)\n",
4253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, context);
4263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
4293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
4303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  value = reinterpret_cast<intptr_t>(function);
4313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
4323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
4333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; function\n",
4343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, value);
4353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Number of incoming arguments.
4383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
4393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
4403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
4413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
4423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
4433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, value, height - 1);
4443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(0 == output_offset);
4473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Builtins* builtins = isolate_->builtins();
4493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Code* adaptor_trampoline =
4503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
4513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  uint32_t pc = reinterpret_cast<uint32_t>(
4523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      adaptor_trampoline->instruction_start() +
4533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
4543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetPc(pc);
4553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
4593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                              int frame_index) {
4609413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  Builtins* builtins = isolate_->builtins();
4619413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
4623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
4633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned height = iterator->Next();
4643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned height_in_bytes = height * kPointerSize;
4653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
4663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("  translating construct stub => height=%d\n", height_in_bytes);
4673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4699413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  unsigned fixed_frame_size = 8 * kPointerSize;
4703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned output_frame_size = height_in_bytes + fixed_frame_size;
4713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate and store the output frame description.
4733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  FrameDescription* output_frame =
4743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      new(output_frame_size) FrameDescription(output_frame_size, function);
4753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameType(StackFrame::CONSTRUCT);
4763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Construct stub can not be topmost or bottommost.
4783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
4793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(output_[frame_index] == NULL);
4803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_[frame_index] = output_frame;
4813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The top address of the frame is computed from the previous
4833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // frame's top and this frame's size.
4843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  uint32_t top_address;
4853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
4863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetTop(top_address);
4873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Compute the incoming parameter translation.
4893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int parameter_count = height;
4903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  unsigned output_offset = output_frame_size;
4913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < parameter_count; ++i) {
4923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    output_offset -= kPointerSize;
4933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    DoTranslateCommand(iterator, frame_index, output_offset);
4943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Read caller's PC from the previous frame.
4973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
4983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  intptr_t callers_pc = output_[frame_index - 1]->GetPc();
4993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, callers_pc);
5003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
5013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
5023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, callers_pc);
5033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Read caller's FP from the previous frame, and set this frame's FP.
5063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
5073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  intptr_t value = output_[frame_index - 1]->GetFp();
5083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
5093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  intptr_t fp_value = top_address + output_offset;
5103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFp(fp_value);
5113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
5123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
5133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           fp_value, output_offset, value);
5143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The context can be gotten from the previous frame.
5173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
5183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  value = output_[frame_index - 1]->GetContext();
5193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
5203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
5213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; context\n",
5223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, value);
5233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // A marker value is used in place of the function.
5263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
5273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
5283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
5293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
5303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; function (construct sentinel)\n",
5313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, value);
5323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5349413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  // The output frame reflects a JSConstructStubGeneric frame.
5359413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  output_offset -= kPointerSize;
5369413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  value = reinterpret_cast<intptr_t>(construct_stub);
5379413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
5389413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  if (FLAG_trace_deopt) {
5399413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; code object\n",
5409413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch           top_address + output_offset, output_offset, value);
5419413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch  }
5429413bcbe2192ed4d701281130490e0ba336debdcBen Murdoch
5433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Number of incoming arguments.
5443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
5453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
5463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
5473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
5483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
5493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, value, height - 1);
5503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Constructor function being invoked by the stub.
5533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
5543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  value = reinterpret_cast<intptr_t>(function);
5553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
5563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
5573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; constructor function\n",
5583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, value);
5593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The newly allocated object was passed as receiver in the artificial
5623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // constructor stub environment created by HEnvironment::CopyForInlining().
5633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_offset -= kPointerSize;
5643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
5653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameSlot(output_offset, value);
5663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_trace_deopt) {
5673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; allocated receiver\n",
5683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           top_address + output_offset, output_offset, value);
5693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(0 == output_offset);
5723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  uint32_t pc = reinterpret_cast<uint32_t>(
5743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      construct_stub->instruction_start() +
5753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      isolate_->heap()->construct_stub_deopt_pc_offset()->value());
5763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetPc(pc);
5773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
5783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// This code is very similar to ia32 code, but relies on register names (fp, sp)
581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// and how the frame is laid out.
5823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
5833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                   int frame_index) {
584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Read the ast node id, function, and frame height for this output frame.
585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int node_id = iterator->Next();
586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned height = iterator->Next();
588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned height_in_bytes = height * kPointerSize;
589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_deopt) {
590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("  translating ");
591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    function->PrintName();
592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes);
593b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The 'fixed' part of the frame consists of the incoming parameters and
596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // the part described by JavaScriptFrameConstants.
597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned fixed_frame_size = ComputeFixedSize(function);
598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned input_frame_size = input_->GetFrameSize();
599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned output_frame_size = height_in_bytes + fixed_frame_size;
600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Allocate and store the output frame description.
602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  FrameDescription* output_frame =
603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      new(output_frame_size) FrameDescription(output_frame_size, function);
6043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  bool is_bottommost = (0 == frame_index);
607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  bool is_topmost = (output_count_ - 1 == frame_index);
608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(frame_index >= 0 && frame_index < output_count_);
609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(output_[frame_index] == NULL);
610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_[frame_index] = output_frame;
611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The top address for the bottommost output frame can be computed from
613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // the input frame pointer and the output frame's height.  For all
614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // subsequent output frames, it can be computed from the previous one's
615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // top address and the current frame's size.
616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  uint32_t top_address;
617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (is_bottommost) {
618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // 2 = context and function in the frame.
619b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    top_address =
620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        input_->GetRegister(fp.code()) - (2 * kPointerSize) - height_in_bytes;
621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetTop(top_address);
625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Compute the incoming parameter translation.
627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int parameter_count = function->shared()->formal_parameter_count() + 1;
628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned output_offset = output_frame_size;
629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned input_offset = input_frame_size;
630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  for (int i = 0; i < parameter_count; ++i) {
631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    output_offset -= kPointerSize;
632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    DoTranslateCommand(iterator, frame_index, output_offset);
633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  input_offset -= (parameter_count * kPointerSize);
635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // There are no translation commands for the caller's pc and fp, the
637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // context, and the function.  Synthesize their values and set them up
638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // explicitly.
639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //
640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The caller's pc for the bottommost output frame is the same as in the
641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // input frame.  For all subsequent output frames, it can be read from the
642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // previous one.  This frame's pc can be computed from the non-optimized
643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // function code and AST id of the bailout.
644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_offset -= kPointerSize;
645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  input_offset -= kPointerSize;
646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  intptr_t value;
647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (is_bottommost) {
648b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    value = input_->GetFrameSlot(input_offset);
649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    value = output_[frame_index - 1]->GetPc();
651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetFrameSlot(output_offset, value);
653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_deopt) {
654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           top_address + output_offset, output_offset, value);
656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The caller's frame pointer for the bottommost output frame is the same
659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // as in the input frame.  For all subsequent output frames, it can be
660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // read from the previous one.  Also compute and set this frame's frame
661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // pointer.
662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_offset -= kPointerSize;
663b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  input_offset -= kPointerSize;
664b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (is_bottommost) {
665b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    value = input_->GetFrameSlot(input_offset);
666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    value = output_[frame_index - 1]->GetFp();
668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
669b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetFrameSlot(output_offset, value);
670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  intptr_t fp_value = top_address + output_offset;
671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(!is_bottommost || input_->GetRegister(fp.code()) == fp_value);
672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetFp(fp_value);
673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (is_topmost) {
674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    output_frame->SetRegister(fp.code(), fp_value);
675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_deopt) {
677b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           fp_value, output_offset, value);
679b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
680b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
681e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For the bottommost output frame the context can be gotten from the input
682e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // frame. For all subsequent output frames it can be gotten from the function
683e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // so long as we don't inline functions that need local contexts.
684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_offset -= kPointerSize;
685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  input_offset -= kPointerSize;
686e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (is_bottommost) {
687e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    value = input_->GetFrameSlot(input_offset);
688e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  } else {
689e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    value = reinterpret_cast<intptr_t>(function->context());
690e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetFrameSlot(output_offset, value);
6923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  output_frame->SetContext(value);
6933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (is_topmost) output_frame->SetRegister(cp.code(), value);
694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_deopt) {
695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; context\n",
696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           top_address + output_offset, output_offset, value);
697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The function was mentioned explicitly in the BEGIN_FRAME.
700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_offset -= kPointerSize;
701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  input_offset -= kPointerSize;
702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  value = reinterpret_cast<uint32_t>(function);
703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The function for the bottommost output frame should also agree with the
704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // input frame.
705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetFrameSlot(output_offset, value);
707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_deopt) {
708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("    0x%08x: [top + %d] <- 0x%08x ; function\n",
709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           top_address + output_offset, output_offset, value);
710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Translate the rest of the frame.
713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  for (unsigned i = 0; i < height; ++i) {
714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    output_offset -= kPointerSize;
715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    DoTranslateCommand(iterator, frame_index, output_offset);
716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(0 == output_offset);
718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Compute this frame's PC, state, and continuation.
720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Code* non_optimized_code = function->shared()->code();
721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  FixedArray* raw_data = non_optimized_code->deoptimization_data();
722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Address start = non_optimized_code->instruction_start();
724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset);
727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetPc(pc_value);
728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (is_topmost) {
729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    output_frame->SetRegister(pc.code(), pc_value);
730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  FullCodeGenerator::State state =
733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FullCodeGenerator::StateField::decode(pc_and_state);
734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  output_frame->SetState(Smi::FromInt(state));
735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
73644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set the continuation for the topmost frame.
7383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (is_topmost && bailout_type_ != DEBUGGER) {
73944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Builtins* builtins = isolate_->builtins();
740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Code* continuation = (bailout_type_ == EAGER)
74144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ? builtins->builtin(Builtins::kNotifyDeoptimized)
74244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        : builtins->builtin(Builtins::kNotifyLazyDeoptimized);
743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    output_frame->SetContinuation(
744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        reinterpret_cast<uint32_t>(continuation->entry()));
745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
7493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
7503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Set the register values. The values are not important as there are no
7513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // callee saved registers in JavaScript frames, so all registers are
7523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // spilled. Registers fp and sp are set to the correct values though.
7533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < Register::kNumRegisters; i++) {
7553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    input_->SetRegister(i, i * 4);
7563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
7573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
7583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
7593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
7603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    input_->SetDoubleRegister(i, 0.0);
7613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
7633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Fill the frame content from the actual data on the frame.
7643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
7653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    input_->SetFrameSlot(i, Memory::uint32_at(tos + i));
7663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
7673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
7683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch#define __ masm()->
771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// This code tries to be close to ia32 code so that any changes can be
773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// easily ported.
774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid Deoptimizer::EntryGenerator::Generate() {
775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GeneratePrologue();
77644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
77744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = masm()->isolate();
77844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CpuFeatures::Scope scope(VFP3);
780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Save all general purpose registers before messing with them.
781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int kNumberOfRegisters = Register::kNumRegisters;
782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Everything but pc, lr and ip which will be saved but not restored.
784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit();
785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int kDoubleRegsSize =
787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      kDoubleSize * DwVfpRegister::kNumAllocatableRegisters;
788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Save all VFP registers before messing with them.
790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  DwVfpRegister first = DwVfpRegister::FromAllocationIndex(0);
791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  DwVfpRegister last =
792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      DwVfpRegister::FromAllocationIndex(
793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          DwVfpRegister::kNumAllocatableRegisters - 1);
794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(last.code() > first.code());
795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT((last.code() - first.code()) ==
796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      (DwVfpRegister::kNumAllocatableRegisters - 1));
797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#ifdef DEBUG
798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i <= (DwVfpRegister::kNumAllocatableRegisters - 1); i++) {
799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT((DwVfpRegister::FromAllocationIndex(i).code() <= last.code()) &&
800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch           (DwVfpRegister::FromAllocationIndex(i).code() >= first.code()));
801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#endif
803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ vstm(db_w, sp, first, last);
804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push all 16 registers (needed to populate FrameDescription::registers_).
80669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // TODO(1588) Note that using pc with stm is deprecated, so we should perhaps
80769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // handle this a bit differently.
808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ stm(db_w, sp, restored_regs  | sp.bit() | lr.bit() | pc.bit());
809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int kSavedRegistersAreaSize =
811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the bailout id from the stack.
814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r2, MemOperand(sp, kSavedRegistersAreaSize));
815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the address of the location in the code object if possible (r3) (return
817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // address for lazy deoptimization) and compute the fp-to-sp delta in
818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // register r4.
819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (type() == EAGER) {
820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(r3, Operand(0));
821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Correct one word for bailout id.
822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
8231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (type() == OSR) {
8241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ mov(r3, lr);
8251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Correct one word for bailout id.
8261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
827b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(r3, lr);
829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Correct two words for bailout id and return address.
830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(r4, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sub(r4, fp, r4);
833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Allocate a new deoptimizer object.
835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Pass four arguments in r0 to r3 and fifth argument on stack.
8368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ PrepareCallCFunction(6, r5);
837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(r1, Operand(type()));  // bailout type,
839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // r2: bailout id already loaded.
840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // r3: code address or 0 already loaded.
841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ str(r4, MemOperand(sp, 0 * kPointerSize));  // Fp-to-sp delta.
8428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ mov(r5, Operand(ExternalReference::isolate_address()));
8438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ str(r5, MemOperand(sp, 1 * kPointerSize));  // Isolate.
844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Call Deoptimizer::New().
8453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
8463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    AllowExternalCallThatCantCauseGC scope(masm());
8473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 6);
8483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Preserve "deoptimizer" object in register r0 and get the input
851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // frame descriptor pointer to r1 (deoptimizer->input_);
852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Copy core registers into FrameDescription::registers_[kNumRegisters].
855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(Register::kNumRegisters == kNumberOfRegisters);
856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  for (int i = 0; i < kNumberOfRegisters; i++) {
8571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    int offset = (i * kPointerSize) + FrameDescription::registers_offset();
858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ldr(r2, MemOperand(sp, i * kPointerSize));
859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ str(r2, MemOperand(r1, offset));
860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Copy VFP registers to
863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // double_registers_[DoubleRegister::kNumAllocatableRegisters]
864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int double_regs_offset = FrameDescription::double_registers_offset();
865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) {
866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    int dst_offset = i * kDoubleSize + double_regs_offset;
867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ vldr(d0, sp, src_offset);
869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ vstr(d0, r1, dst_offset);
870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Remove the bailout id, eventually return address, and the saved registers
873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // from the stack.
8741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (type() == EAGER || type() == OSR) {
875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
877b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(sp, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Compute a pointer to the unwinding limit in register r2; that is
881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // the first stack slot not part of the input frame.
882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r2, MemOperand(r1, FrameDescription::frame_size_offset()));
883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ add(r2, r2, sp);
884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
885b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Unwind the stack down to - but not including - the unwinding
886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // limit and copy the contents of the activation frame to the input
887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // frame description.
888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ add(r3,  r1, Operand(FrameDescription::frame_content_offset()));
889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label pop_loop;
890b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&pop_loop);
891b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(r4);
892b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ str(r4, MemOperand(r3, 0));
893b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ add(r3, r3, Operand(sizeof(uint32_t)));
894b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(r2, sp);
895b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ b(ne, &pop_loop);
896b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
897b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Compute the output frame in the deoptimizer.
898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(r0);  // Preserve deoptimizer object across call.
899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // r0: deoptimizer object; r1: scratch.
900b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ PrepareCallCFunction(1, r1);
901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Call Deoptimizer::ComputeOutputFrames().
9023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
9033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    AllowExternalCallThatCantCauseGC scope(masm());
9043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(
9053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::compute_output_frames_function(isolate), 1);
9063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(r0);  // Restore deoptimizer object (class Deoptimizer).
908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Replace the current (input) frame with the output frames.
910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label outer_push_loop, inner_push_loop;
911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Outer loop state: r0 = current "FrameDescription** output_",
912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // r1 = one past the last FrameDescription**.
913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r1, MemOperand(r0, Deoptimizer::output_count_offset()));
914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r0, MemOperand(r0, Deoptimizer::output_offset()));  // r0 is output_.
915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ add(r1, r0, Operand(r1, LSL, 2));
916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&outer_push_loop);
917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Inner loop state: r2 = current FrameDescription*, r3 = loop index.
918b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r2, MemOperand(r0, 0));  // output_[ix]
919b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset()));
920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&inner_push_loop);
921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sub(r3, r3, Operand(sizeof(uint32_t)));
922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ add(r6, r2, Operand(r3));
923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset()));
924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(r7);
925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(r3, Operand(0));
926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ b(ne, &inner_push_loop);  // test for gt?
927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ add(r0, r0, Operand(kPointerSize));
928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(r0, r1);
929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ b(lt, &outer_push_loop);
930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push state, pc, and continuation from the last output frame.
932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (type() != OSR) {
933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ldr(r6, MemOperand(r2, FrameDescription::state_offset()));
934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(r6);
935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset()));
938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(r6);
939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset()));
940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(r6);
941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push the registers from the last output frame.
943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
9441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    int offset = (i * kPointerSize) + FrameDescription::registers_offset();
945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ldr(r6, MemOperand(r2, offset));
946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(r6);
947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Restore the registers from the stack.
950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ldm(ia_w, sp, restored_regs);  // all but pc registers.
951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ip);  // remove sp
952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ip);  // remove lr
953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
954c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  __ InitializeRootRegister();
955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ip);  // remove pc
957b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(r7);  // get continuation, leave pc on stack
958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(lr);
959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Jump(r7);
960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ stop("Unreachable.");
961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid Deoptimizer::TableEntryGenerator::GeneratePrologue() {
965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Create a sequence of deoptimization entries. Note that any
966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // registers may be still live.
967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label done;
968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  for (int i = 0; i < count(); i++) {
969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    int start = masm()->pc_offset();
970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    USE(start);
971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    if (type() == EAGER) {
972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ nop();
973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    } else {
974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Emulate ia32 like call by pushing return address to stack.
975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ push(lr);
976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ip, Operand(i));
978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(ip);
979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ b(&done);
980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ASSERT(masm()->pc_offset() - start == table_entry_size_);
981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&done);
983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#undef __
986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} }  // namespace v8::internal
988