1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if V8_TARGET_ARCH_X87
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h"
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/deoptimizer.h"
9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/full-codegen/full-codegen.h"
10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/register-configuration.h"
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/safepoint-table.h"
12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/x87/frames-x87.h"
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 {
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal {
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochconst int Deoptimizer::table_entry_size_ = 10;
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochint Deoptimizer::patch_size() {
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return Assembler::kCallInstructionLength;
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Isolate* isolate = code->GetIsolate();
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  HandleScope scope(isolate);
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Compute the size of relocation information needed for the code
30958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  // patching in Deoptimizer::PatchCodeForDeoptimization below.
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int min_reloc_size = 0;
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int prev_pc_offset = 0;
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DeoptimizationInputData* deopt_data =
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DeoptimizationInputData::cast(code->deoptimization_data());
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int pc_offset = deopt_data->Pc(i)->value();
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (pc_offset == -1) continue;
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK_GE(pc_offset, prev_pc_offset);
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int pc_delta = pc_offset - prev_pc_offset;
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // if encodable with small pc delta encoding and up to 6 bytes
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // otherwise.
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (pc_delta <= RelocInfo::kMaxSmallPCDelta) {
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      min_reloc_size += 2;
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    } else {
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      min_reloc_size += 6;
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    prev_pc_offset = pc_offset;
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // If the relocation information is not big enough we create a new
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // relocation info object that is padded with comments to make it
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // big enough for lazy doptimization.
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int reloc_length = code->relocation_info()->length();
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (min_reloc_size > reloc_length) {
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int comment_reloc_size = RelocInfo::kMinRelocCommentSize;
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Padding needed.
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int min_padding = min_reloc_size - reloc_length;
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Number of comments needed to take up at least that much space.
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int additional_comments =
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        (min_padding + comment_reloc_size - 1) / comment_reloc_size;
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Actual padding size.
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int padding = additional_comments * comment_reloc_size;
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Allocate new relocation info and copy old relocation to the end
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // of the new relocation info array because relocation info is
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // written and read backwards.
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Factory* factory = isolate->factory();
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Handle<ByteArray> new_reloc =
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        factory->NewByteArray(reloc_length + padding, TENURED);
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    MemCopy(new_reloc->GetDataStartAddress() + padding,
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            code->relocation_info()->GetDataStartAddress(), reloc_length);
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Create a relocation writer to write the comments in the padding
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // space. Use position 0 for everything to ensure short encoding.
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    RelocInfoWriter reloc_info_writer(
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        new_reloc->GetDataStartAddress() + padding, 0);
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    intptr_t comment_string
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        = reinterpret_cast<intptr_t>(RelocInfo::kFillerCommentString);
78014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    RelocInfo rinfo(isolate, 0, RelocInfo::COMMENT, comment_string, NULL);
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (int i = 0; i < additional_comments; ++i) {
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      byte* pos_before = reloc_info_writer.pos();
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      reloc_info_writer.Write(&rinfo);
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DCHECK(RelocInfo::kMinRelocCommentSize ==
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             pos_before - reloc_info_writer.pos());
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Replace relocation information on the code object.
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    code->set_relocation_info(*new_reloc);
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Address code_start_address = code->instruction_start();
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (FLAG_zap_code_space) {
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Fail hard and early if we enter this code object again.
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    byte* pointer = code->FindCodeAgeSequence();
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (pointer != NULL) {
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      pointer += kNoCodeAgeSequenceLength;
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    } else {
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      pointer = code->instruction_start();
103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    CodePatcher patcher(isolate, pointer, 1);
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    patcher.masm()->int3();
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DeoptimizationInputData* data =
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        DeoptimizationInputData::cast(code->deoptimization_data());
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int osr_offset = data->OsrPcOffset()->value();
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (osr_offset > 0) {
111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      CodePatcher osr_patcher(isolate, code->instruction_start() + osr_offset,
112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                              1);
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      osr_patcher.masm()->int3();
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // We will overwrite the code's relocation info in-place. Relocation info
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // is written backward. The relocation info is the payload of a byte
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // array.  Later on we will slide this to the start of the byte array and
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // create a filler object in the remaining space.
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ByteArray* reloc_info = code->relocation_info();
122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Address reloc_end_address = reloc_info->address() + reloc_info->Size();
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address);
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Since the call is a relative encoding, write new
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // reloc info.  We do not need any of the existing reloc info because the
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // existing code will not be used again (we zap it in debug builds).
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Emit call to lazy deoptimization at all lazy deopt points.
130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DeoptimizationInputData* deopt_data =
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DeoptimizationInputData::cast(code->deoptimization_data());
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Address prev_call_address = NULL;
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // For each LLazyBailout instruction insert a call to the corresponding
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // deoptimization entry.
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (deopt_data->Pc(i)->value() == -1) continue;
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Patch lazy deoptimization entry.
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Address call_address = code_start_address + deopt_data->Pc(i)->value();
141014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    CodePatcher patcher(isolate, call_address, patch_size());
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY);
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    patcher.masm()->call(deopt_entry, RelocInfo::NONE32);
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // We use RUNTIME_ENTRY for deoptimization bailouts.
145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    RelocInfo rinfo(isolate, call_address + 1,  // 1 after the call opcode.
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    RelocInfo::RUNTIME_ENTRY,
147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                    reinterpret_cast<intptr_t>(deopt_entry), NULL);
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    reloc_info_writer.Write(&rinfo);
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK_GE(reloc_info_writer.pos(),
150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              reloc_info->address() + ByteArray::kHeaderSize);
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(prev_call_address == NULL ||
152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch           call_address >= prev_call_address + patch_size());
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(call_address + patch_size() <= code->instruction_end());
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    prev_call_address = call_address;
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif
157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Move the relocation info to the beginning of the byte array.
160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int new_reloc_length = reloc_end_address - reloc_info_writer.pos();
161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  MemMove(code->relocation_start(), reloc_info_writer.pos(), new_reloc_length);
162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Right trim the relocation info to free up remaining space.
164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int delta = reloc_info->length() - new_reloc_length;
165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (delta > 0) {
166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    isolate->heap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(
167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        reloc_info, delta);
168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Set the register values. The values are not important as there are no
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // callee saved registers in JavaScript frames, so all registers are
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // spilled. Registers ebp and esp are set to the correct values though.
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int i = 0; i < Register::kNumRegisters; i++) {
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    input_->SetRegister(i, i * 4);
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  input_->SetRegister(esp.code(), reinterpret_cast<intptr_t>(frame->sp()));
181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  input_->SetRegister(ebp.code(), reinterpret_cast<intptr_t>(frame->fp()));
182014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  for (int i = 0; i < X87Register::kMaxNumRegisters; i++) {
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    input_->SetDoubleRegister(i, 0.0);
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Fill the frame content from the actual data on the frame.
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    input_->SetFrameSlot(i, Memory::uint32_at(tos + i));
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::SetPlatformCompiledStubRegisters(
194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameDescription* output_frame, CodeStubDescriptor* descriptor) {
195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  intptr_t handler =
196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      reinterpret_cast<intptr_t>(descriptor->deoptimization_handler());
197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int params = descriptor->GetHandlerParameterCount();
198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  output_frame->SetRegister(eax.code(), params);
199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  output_frame->SetRegister(ebx.code(), handler);
200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
204014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  for (int i = 0; i < X87Register::kMaxNumRegisters; ++i) {
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    double double_value = input_->GetDoubleRegister(i);
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    output_frame->SetDoubleRegister(i, double_value);
207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochbool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
212014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int parameter_count =
213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      function->shared()->internal_formal_parameter_count() + 1;
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  unsigned input_frame_size = input_->GetFrameSize();
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  unsigned alignment_state_offset =
216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      input_frame_size - parameter_count * kPointerSize -
217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      StandardFrameConstants::kFixedFrameSize -
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      kPointerSize;
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(JavaScriptFrameConstants::kDynamicAlignmentStateOffset ==
220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      JavaScriptFrameConstants::kLocal0Offset);
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int32_t alignment_state = input_->GetFrameSlot(alignment_state_offset);
222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return (alignment_state == kAlignmentPaddingPushed);
223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define __ masm()->
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
228014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Deoptimizer::TableEntryGenerator::Generate() {
229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GeneratePrologue();
230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Save all general purpose registers before messing with them.
232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const int kNumberOfRegisters = Register::kNumRegisters;
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int kDoubleRegsSize = kDoubleSize * X87Register::kMaxNumRegisters;
235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Reserve space for x87 fp registers.
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(esp, Immediate(kDoubleRegsSize));
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pushad();
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
242014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ mov(Operand::StaticVariable(c_entry_fp_address), ebp);
243014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // GP registers are safe to use now.
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Save used x87 fp registers in correct position of previous reserve space.
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label loop, done;
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the layout of x87 stack.
248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(esp, Immediate(kPointerSize));
249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ fistp_s(MemOperand(esp, 0));
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(eax);
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Preserve stack layout in edi
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(edi, eax);
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the x87 stack depth, the first 3 bits.
254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ecx, eax);
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ and_(ecx, 0x7);
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(zero, &done, Label::kNear);
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&loop);
259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ shr(eax, 0x3);
260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, eax);
261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ and_(ebx, 0x7);  // Extract the st_x index into ebx.
262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Pop TOS to the correct position. The disp(0x20) is due to pushad.
263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The st_i should be saved to (esp + ebx * kDoubleSize + 0x20).
264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ fstp_d(Operand(esp, ebx, times_8, 0x20));
265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ dec(ecx);  // Decrease stack depth.
266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(not_zero, &loop, Label::kNear);
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&done);
268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const int kSavedRegistersAreaSize =
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      kNumberOfRegisters * kPointerSize + kDoubleRegsSize;
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the bailout id from the stack.
273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(esp, kSavedRegistersAreaSize));
274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the address of the location in the code object
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // and compute the fp-to-sp delta in register edx.
277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ecx, Operand(esp, kSavedRegistersAreaSize + 1 * kPointerSize));
278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(edx, Operand(esp, kSavedRegistersAreaSize + 2 * kPointerSize));
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(edx, ebp);
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ neg(edx);
282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(edi);
284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Allocate a new deoptimizer object.
285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ PrepareCallCFunction(6, eax);
286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 0 * kPointerSize), eax);  // Function.
288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 1 * kPointerSize), Immediate(type()));  // Bailout type.
289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 2 * kPointerSize), ebx);  // Bailout id.
290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Code address or 0.
291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 4 * kPointerSize), edx);  // Fp-to-sp delta.
292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 5 * kPointerSize),
293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch         Immediate(ExternalReference::isolate_address(isolate())));
294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    AllowExternalCallThatCantCauseGC scope(masm());
296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(edi);
300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Preserve deoptimizer object in register eax and get the input
302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // frame descriptor pointer.
303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(eax, Deoptimizer::input_offset()));
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Fill in the input registers.
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int offset = (i * kPointerSize) + FrameDescription::registers_offset();
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ pop(Operand(ebx, offset));
309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int double_regs_offset = FrameDescription::double_registers_offset();
312014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const RegisterConfiguration* config =
313014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Fill in the double input registers.
315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int i = 0; i < X87Register::kMaxNumAllocatableRegisters; ++i) {
316014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    int code = config->GetAllocatableDoubleCode(i);
317014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    int dst_offset = code * kDoubleSize + double_regs_offset;
318014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    int src_offset = code * kDoubleSize;
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ fld_d(Operand(esp, src_offset));
320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ fstp_d(Operand(ebx, dst_offset));
321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Clear FPU all exceptions.
324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // TODO(ulan): Find out why the TOP register is not zero here in some cases,
325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // and check that the generated code never deoptimizes with unbalanced stack.
326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ fnclex();
327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Remove the bailout id, return address and the double registers.
329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ add(esp, Immediate(kDoubleRegsSize + 2 * kPointerSize));
330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Compute a pointer to the unwinding limit in register ecx; that is
332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // the first stack slot not part of the input frame.
333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset()));
334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ add(ecx, esp);
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Unwind the stack down to - but not including - the unwinding
337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // limit and copy the contents of the activation frame to the input
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // frame description.
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(edx, Operand(ebx, FrameDescription::frame_content_offset()));
340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label pop_loop_header;
341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ jmp(&pop_loop_header);
342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label pop_loop;
343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&pop_loop);
344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(Operand(edx, 0));
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ add(edx, Immediate(sizeof(uint32_t)));
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&pop_loop_header);
347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(ecx, esp);
348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(not_equal, &pop_loop);
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Compute the output frame in the deoptimizer.
351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(edi);
352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(eax);
353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ PrepareCallCFunction(1, ebx);
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(Operand(esp, 0 * kPointerSize), eax);
355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    AllowExternalCallThatCantCauseGC scope(masm());
357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CallCFunction(
358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ExternalReference::compute_output_frames_function(isolate()), 1);
359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(eax);
361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(edi);
362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // If frame was dynamically aligned, pop padding.
364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label no_padding;
365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(Operand(eax, Deoptimizer::has_alignment_padding_offset()),
366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch         Immediate(0));
367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(equal, &no_padding);
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ pop(ecx);
369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (FLAG_debug_code) {
370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ cmp(ecx, Immediate(kAlignmentZapValue));
371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ Assert(equal, kAlignmentMarkerExpected);
372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&no_padding);
374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Replace the current frame with the output frames.
376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label outer_push_loop, inner_push_loop,
377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      outer_loop_header, inner_loop_header;
378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Outer loop state: eax = current FrameDescription**, edx = one past the
379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // last FrameDescription**.
380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(edx, Operand(eax, Deoptimizer::output_count_offset()));
381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, Operand(eax, Deoptimizer::output_offset()));
382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(edx, Operand(eax, edx, times_4, 0));
383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ jmp(&outer_loop_header);
384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&outer_push_loop);
385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Inner loop state: ebx = current FrameDescription*, ecx = loop index.
386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ebx, Operand(eax, 0));
387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset()));
388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ jmp(&inner_loop_header);
389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&inner_push_loop);
390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(ecx, Immediate(sizeof(uint32_t)));
391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(Operand(ebx, ecx, times_1, FrameDescription::frame_content_offset()));
392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&inner_loop_header);
393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ test(ecx, ecx);
394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(not_zero, &inner_push_loop);
395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ add(eax, Immediate(kPointerSize));
396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&outer_loop_header);
397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmp(eax, edx);
398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(below, &outer_push_loop);
399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // In case of a failed STUB, we have to restore the x87 stack.
402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // x87 stack layout is in edi.
403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label loop2, done2;
404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Get the x87 stack depth, the first 3 bits.
405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(ecx, edi);
406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ and_(ecx, 0x7);
407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(zero, &done2, Label::kNear);
408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ lea(ecx, Operand(ecx, ecx, times_2, 0));
410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&loop2);
411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ mov(eax, edi);
412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ shr_cl(eax);
413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ and_(eax, 0x7);
414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ fld_d(Operand(ebx, eax, times_8, double_regs_offset));
415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ sub(ecx, Immediate(0x3));
416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(not_zero, &loop2, Label::kNear);
417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&done2);
418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Push state, pc, and continuation from the last output frame.
420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(Operand(ebx, FrameDescription::state_offset()));
421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(Operand(ebx, FrameDescription::pc_offset()));
422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ push(Operand(ebx, FrameDescription::continuation_offset()));
423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
424b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Push the registers from the last output frame.
426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int i = 0; i < kNumberOfRegisters; i++) {
427b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int offset = (i * kPointerSize) + FrameDescription::registers_offset();
428b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push(Operand(ebx, offset));
429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Restore the registers from the stack.
432b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ popad();
433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Return to the continuation point.
435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
438b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
439b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::TableEntryGenerator::GeneratePrologue() {
440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Create a sequence of deoptimization entries.
441b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label done;
442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int i = 0; i < count(); i++) {
443b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int start = masm()->pc_offset();
444b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    USE(start);
445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ push_imm32(i);
446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ jmp(&done);
447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(masm()->pc_offset() - start == table_entry_size_);
448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
449b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&done);
450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
453b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  SetFrameSlot(offset, value);
455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
456b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
458b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  SetFrameSlot(offset, value);
460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
463b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
464014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // No embedded constant pool support.
465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  UNREACHABLE();
466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef __
470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
472014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
473014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
475b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif  // V8_TARGET_ARCH_X87
476