blob: 611fbaaf96511f9c2666f7f287ea4ed718d221e5 [file] [log] [blame]
lrn@chromium.org7516f052011-03-30 08:52:27 +00001// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "codegen.h"
31#include "deoptimizer.h"
32#include "full-codegen.h"
33#include "safepoint-table.h"
34
lrn@chromium.org7516f052011-03-30 08:52:27 +000035namespace v8 {
36namespace internal {
37
38
lrn@chromium.org7516f052011-03-30 08:52:27 +000039int Deoptimizer::patch_size() {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000040 const int kCallInstructionSizeInWords = 4;
lrn@chromium.org7516f052011-03-30 08:52:27 +000041 return kCallInstructionSizeInWords * Assembler::kInstrSize;
42}
43
44
45void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000046 HandleScope scope;
47 AssertNoAllocation no_allocation;
48
49 if (!function->IsOptimized()) return;
50
51 // Get the optimized code.
52 Code* code = function->code();
erikcorry0ad885c2011-11-21 13:51:57 +000053 Address code_start_address = code->instruction_start();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000054
55 // Invalidate the relocation information, as it will become invalid by the
56 // code patching below, and is not needed any more.
57 code->InvalidateRelocation();
58
erikcorry0ad885c2011-11-21 13:51:57 +000059 // For each LLazyBailout instruction insert a call to the corresponding
60 // deoptimization entry.
61 DeoptimizationInputData* deopt_data =
62 DeoptimizationInputData::cast(code->deoptimization_data());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000063#ifdef DEBUG
erikcorry0ad885c2011-11-21 13:51:57 +000064 Address prev_call_address = NULL;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000065#endif
erikcorry0ad885c2011-11-21 13:51:57 +000066 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
67 if (deopt_data->Pc(i)->value() == -1) continue;
68 Address call_address = code_start_address + deopt_data->Pc(i)->value();
69 Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
70 int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
71 RelocInfo::NONE);
72 int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
73 ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
74 ASSERT(call_size_in_bytes <= patch_size());
75 CodePatcher patcher(call_address, call_size_in_words);
76 patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
77 ASSERT(prev_call_address == NULL ||
78 call_address >= prev_call_address + patch_size());
79 ASSERT(call_address + patch_size() <= code->instruction_end());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000080
81#ifdef DEBUG
erikcorry0ad885c2011-11-21 13:51:57 +000082 prev_call_address = call_address;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000083#endif
erikcorry0ad885c2011-11-21 13:51:57 +000084 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000085
86 Isolate* isolate = code->GetIsolate();
87
88 // Add the deoptimizing code to the list.
89 DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
90 DeoptimizerData* data = isolate->deoptimizer_data();
91 node->set_next(data->deoptimizing_code_list_);
92 data->deoptimizing_code_list_ = node;
93
94 // We might be in the middle of incremental marking with compaction.
95 // Tell collector to treat this code object in a special way and
96 // ignore all slots that might have been recorded on it.
97 isolate->heap()->mark_compact_collector()->InvalidateCode(code);
98
99 // Set the code for the function to non-optimized version.
100 function->ReplaceCode(function->shared()->code());
101
102 if (FLAG_trace_deopt) {
103 PrintF("[forced deoptimization: ");
104 function->PrintName();
105 PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
106#ifdef DEBUG
107 if (FLAG_print_code) {
108 code->PrintLn();
109 }
110#endif
111 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000112}
113
114
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000115void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
116 Address pc_after,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000117 Code* check_code,
118 Code* replacement_code) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000119 const int kInstrSize = Assembler::kInstrSize;
120 // This structure comes from FullCodeGenerator::EmitStackCheck.
121 // The call of the stack guard check has the following form:
122 // sltu at, sp, t0
123 // beq at, zero_reg, ok
124 // lui t9, <stack guard address> upper
125 // ori t9, <stack guard address> lower
126 // jalr t9
127 // nop
128 // ----- pc_after points here
129
130 ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
131
132 // Replace the sltu instruction with load-imm 1 to at, so beq is not taken.
133 CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
134 patcher.masm()->addiu(at, zero_reg, 1);
135
136 // Replace the stack check address in the load-immediate (lui/ori pair)
137 // with the entry address of the replacement code.
138 ASSERT(reinterpret_cast<uint32_t>(
139 Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
140 reinterpret_cast<uint32_t>(check_code->entry()));
141 Assembler::set_target_address_at(pc_after - 4 * kInstrSize,
142 replacement_code->entry());
143
144 // We patched the code to the following form:
145 // addiu at, zero_reg, 1
146 // beq at, zero_reg, ok ;; Not changed
147 // lui t9, <on-stack replacement address> upper
148 // ori t9, <on-stack replacement address> lower
149 // jalr t9 ;; Not changed
150 // nop ;; Not changed
151 // ----- pc_after points here
152
153 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
154 unoptimized_code, pc_after - 4 * kInstrSize, replacement_code);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000155}
156
157
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000158void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
159 Address pc_after,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000160 Code* check_code,
161 Code* replacement_code) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000162 // Exact opposite of the function above.
163 const int kInstrSize = Assembler::kInstrSize;
164 ASSERT(Assembler::IsAddImmediate(
165 Assembler::instr_at(pc_after - 6 * kInstrSize)));
166 ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
167
168 // Restore the sltu instruction so beq can be taken again.
169 CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
170 patcher.masm()->sltu(at, sp, t0);
171
172 // Replace the on-stack replacement address in the load-immediate (lui/ori
173 // pair) with the entry address of the normal stack-check code.
174 ASSERT(reinterpret_cast<uint32_t>(
175 Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
176 reinterpret_cast<uint32_t>(replacement_code->entry()));
177 Assembler::set_target_address_at(pc_after - 4 * kInstrSize,
178 check_code->entry());
179
180 check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
181 unoptimized_code, pc_after - 4 * kInstrSize, check_code);
182}
183
184
185static int LookupBailoutId(DeoptimizationInputData* data, unsigned ast_id) {
186 ByteArray* translations = data->TranslationByteArray();
187 int length = data->DeoptCount();
188 for (int i = 0; i < length; i++) {
189 if (static_cast<unsigned>(data->AstId(i)->value()) == ast_id) {
190 TranslationIterator it(translations, data->TranslationIndex(i)->value());
191 int value = it.Next();
192 ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
193 // Read the number of frames.
194 value = it.Next();
195 if (value == 1) return i;
196 }
197 }
198 UNREACHABLE();
199 return -1;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000200}
201
202
203void Deoptimizer::DoComputeOsrOutputFrame() {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000204 DeoptimizationInputData* data = DeoptimizationInputData::cast(
205 optimized_code_->deoptimization_data());
206 unsigned ast_id = data->OsrAstId()->value();
207
208 int bailout_id = LookupBailoutId(data, ast_id);
209 unsigned translation_index = data->TranslationIndex(bailout_id)->value();
210 ByteArray* translations = data->TranslationByteArray();
211
212 TranslationIterator iterator(translations, translation_index);
213 Translation::Opcode opcode =
214 static_cast<Translation::Opcode>(iterator.Next());
215 ASSERT(Translation::BEGIN == opcode);
216 USE(opcode);
217 int count = iterator.Next();
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000218 iterator.Skip(1); // Drop JS frame count.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000219 ASSERT(count == 1);
220 USE(count);
221
222 opcode = static_cast<Translation::Opcode>(iterator.Next());
223 USE(opcode);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000224 ASSERT(Translation::JS_FRAME == opcode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000225 unsigned node_id = iterator.Next();
226 USE(node_id);
227 ASSERT(node_id == ast_id);
228 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next()));
229 USE(function);
230 ASSERT(function == function_);
231 unsigned height = iterator.Next();
232 unsigned height_in_bytes = height * kPointerSize;
233 USE(height_in_bytes);
234
235 unsigned fixed_size = ComputeFixedSize(function_);
236 unsigned input_frame_size = input_->GetFrameSize();
237 ASSERT(fixed_size + height_in_bytes == input_frame_size);
238
239 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize;
240 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
241 unsigned outgoing_size = outgoing_height * kPointerSize;
242 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
243 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call.
244
245 if (FLAG_trace_osr) {
246 PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
247 reinterpret_cast<intptr_t>(function_));
248 function_->PrintName();
249 PrintF(" => node=%u, frame=%d->%d]\n",
250 ast_id,
251 input_frame_size,
252 output_frame_size);
253 }
254
255 // There's only one output frame in the OSR case.
256 output_count_ = 1;
257 output_ = new FrameDescription*[1];
258 output_[0] = new(output_frame_size) FrameDescription(
259 output_frame_size, function_);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000260 output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000261
262 // Clear the incoming parameters in the optimized frame to avoid
263 // confusing the garbage collector.
264 unsigned output_offset = output_frame_size - kPointerSize;
265 int parameter_count = function_->shared()->formal_parameter_count() + 1;
266 for (int i = 0; i < parameter_count; ++i) {
267 output_[0]->SetFrameSlot(output_offset, 0);
268 output_offset -= kPointerSize;
269 }
270
271 // Translate the incoming parameters. This may overwrite some of the
272 // incoming argument slots we've just cleared.
273 int input_offset = input_frame_size - kPointerSize;
274 bool ok = true;
275 int limit = input_offset - (parameter_count * kPointerSize);
276 while (ok && input_offset > limit) {
277 ok = DoOsrTranslateCommand(&iterator, &input_offset);
278 }
279
280 // There are no translation commands for the caller's pc and fp, the
281 // context, and the function. Set them up explicitly.
282 for (int i = StandardFrameConstants::kCallerPCOffset;
283 ok && i >= StandardFrameConstants::kMarkerOffset;
284 i -= kPointerSize) {
285 uint32_t input_value = input_->GetFrameSlot(input_offset);
286 if (FLAG_trace_osr) {
287 const char* name = "UNKNOWN";
288 switch (i) {
289 case StandardFrameConstants::kCallerPCOffset:
290 name = "caller's pc";
291 break;
292 case StandardFrameConstants::kCallerFPOffset:
293 name = "fp";
294 break;
295 case StandardFrameConstants::kContextOffset:
296 name = "context";
297 break;
298 case StandardFrameConstants::kMarkerOffset:
299 name = "function";
300 break;
301 }
302 PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
303 output_offset,
304 input_value,
305 input_offset,
306 name);
307 }
308
309 output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
310 input_offset -= kPointerSize;
311 output_offset -= kPointerSize;
312 }
313
314 // Translate the rest of the frame.
315 while (ok && input_offset >= 0) {
316 ok = DoOsrTranslateCommand(&iterator, &input_offset);
317 }
318
319 // If translation of any command failed, continue using the input frame.
320 if (!ok) {
321 delete output_[0];
322 output_[0] = input_;
323 output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
324 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000325 // Set up the frame pointer and the context pointer.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000326 output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code()));
327 output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code()));
328
329 unsigned pc_offset = data->OsrPcOffset()->value();
330 uint32_t pc = reinterpret_cast<uint32_t>(
331 optimized_code_->entry() + pc_offset);
332 output_[0]->SetPc(pc);
333 }
334 Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR);
335 output_[0]->SetContinuation(
336 reinterpret_cast<uint32_t>(continuation->entry()));
337
338 if (FLAG_trace_osr) {
339 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
340 ok ? "finished" : "aborted",
341 reinterpret_cast<intptr_t>(function));
342 function->PrintName();
343 PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
344 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000345}
346
347
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000348void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
349 int frame_index) {
350 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
351 unsigned height = iterator->Next();
352 unsigned height_in_bytes = height * kPointerSize;
353 if (FLAG_trace_deopt) {
354 PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
355 }
356
357 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000358 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
359
360 // Allocate and store the output frame description.
361 FrameDescription* output_frame =
362 new(output_frame_size) FrameDescription(output_frame_size, function);
363 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
364
365 // Arguments adaptor can not be topmost or bottommost.
366 ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
367 ASSERT(output_[frame_index] == NULL);
368 output_[frame_index] = output_frame;
369
370 // The top address of the frame is computed from the previous
371 // frame's top and this frame's size.
372 uint32_t top_address;
373 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
374 output_frame->SetTop(top_address);
375
376 // Compute the incoming parameter translation.
377 int parameter_count = height;
378 unsigned output_offset = output_frame_size;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000379 for (int i = 0; i < parameter_count; ++i) {
380 output_offset -= kPointerSize;
381 DoTranslateCommand(iterator, frame_index, output_offset);
382 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000383
384 // Read caller's PC from the previous frame.
385 output_offset -= kPointerSize;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000386 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
387 output_frame->SetFrameSlot(output_offset, callers_pc);
388 if (FLAG_trace_deopt) {
389 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
390 top_address + output_offset, output_offset, callers_pc);
391 }
392
393 // Read caller's FP from the previous frame, and set this frame's FP.
394 output_offset -= kPointerSize;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000395 intptr_t value = output_[frame_index - 1]->GetFp();
396 output_frame->SetFrameSlot(output_offset, value);
397 intptr_t fp_value = top_address + output_offset;
398 output_frame->SetFp(fp_value);
399 if (FLAG_trace_deopt) {
400 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
401 fp_value, output_offset, value);
402 }
403
404 // A marker value is used in place of the context.
405 output_offset -= kPointerSize;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000406 intptr_t context = reinterpret_cast<intptr_t>(
407 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
408 output_frame->SetFrameSlot(output_offset, context);
409 if (FLAG_trace_deopt) {
410 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context (adaptor sentinel)\n",
411 top_address + output_offset, output_offset, context);
412 }
413
414 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
415 output_offset -= kPointerSize;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000416 value = reinterpret_cast<intptr_t>(function);
417 output_frame->SetFrameSlot(output_offset, value);
418 if (FLAG_trace_deopt) {
419 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
420 top_address + output_offset, output_offset, value);
421 }
422
423 // Number of incoming arguments.
424 output_offset -= kPointerSize;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000425 value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
426 output_frame->SetFrameSlot(output_offset, value);
427 if (FLAG_trace_deopt) {
428 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
429 top_address + output_offset, output_offset, value, height - 1);
430 }
431
432 ASSERT(0 == output_offset);
433
434 Builtins* builtins = isolate_->builtins();
435 Code* adaptor_trampoline =
436 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
437 uint32_t pc = reinterpret_cast<uint32_t>(
438 adaptor_trampoline->instruction_start() +
439 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
440 output_frame->SetPc(pc);
441}
442
443
ulan@chromium.org812308e2012-02-29 15:58:45 +0000444void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
445 int frame_index) {
446 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
447 unsigned height = iterator->Next();
448 unsigned height_in_bytes = height * kPointerSize;
449 if (FLAG_trace_deopt) {
450 PrintF(" translating construct stub => height=%d\n", height_in_bytes);
451 }
452
453 unsigned fixed_frame_size = 7 * kPointerSize;
454 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
455
456 // Allocate and store the output frame description.
457 FrameDescription* output_frame =
458 new(output_frame_size) FrameDescription(output_frame_size, function);
459 output_frame->SetFrameType(StackFrame::CONSTRUCT);
460
461 // Construct stub can not be topmost or bottommost.
462 ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
463 ASSERT(output_[frame_index] == NULL);
464 output_[frame_index] = output_frame;
465
466 // The top address of the frame is computed from the previous
467 // frame's top and this frame's size.
468 uint32_t top_address;
469 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
470 output_frame->SetTop(top_address);
471
472 // Compute the incoming parameter translation.
473 int parameter_count = height;
474 unsigned output_offset = output_frame_size;
475 for (int i = 0; i < parameter_count; ++i) {
476 output_offset -= kPointerSize;
477 DoTranslateCommand(iterator, frame_index, output_offset);
478 }
479
480 // Read caller's PC from the previous frame.
481 output_offset -= kPointerSize;
482 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
483 output_frame->SetFrameSlot(output_offset, callers_pc);
484 if (FLAG_trace_deopt) {
485 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
486 top_address + output_offset, output_offset, callers_pc);
487 }
488
489 // Read caller's FP from the previous frame, and set this frame's FP.
490 output_offset -= kPointerSize;
491 intptr_t value = output_[frame_index - 1]->GetFp();
492 output_frame->SetFrameSlot(output_offset, value);
493 intptr_t fp_value = top_address + output_offset;
494 output_frame->SetFp(fp_value);
495 if (FLAG_trace_deopt) {
496 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
497 fp_value, output_offset, value);
498 }
499
500 // The context can be gotten from the previous frame.
501 output_offset -= kPointerSize;
502 value = output_[frame_index - 1]->GetContext();
503 output_frame->SetFrameSlot(output_offset, value);
504 if (FLAG_trace_deopt) {
505 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
506 top_address + output_offset, output_offset, value);
507 }
508
509 // A marker value is used in place of the function.
510 output_offset -= kPointerSize;
511 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
512 output_frame->SetFrameSlot(output_offset, value);
513 if (FLAG_trace_deopt) {
514 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function (construct sentinel)\n",
515 top_address + output_offset, output_offset, value);
516 }
517
518 // Number of incoming arguments.
519 output_offset -= kPointerSize;
520 value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
521 output_frame->SetFrameSlot(output_offset, value);
522 if (FLAG_trace_deopt) {
523 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
524 top_address + output_offset, output_offset, value, height - 1);
525 }
526
527 // Constructor function being invoked by the stub.
528 output_offset -= kPointerSize;
529 value = reinterpret_cast<intptr_t>(function);
530 output_frame->SetFrameSlot(output_offset, value);
531 if (FLAG_trace_deopt) {
532 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; constructor function\n",
533 top_address + output_offset, output_offset, value);
534 }
535
536 // The newly allocated object was passed as receiver in the artificial
537 // constructor stub environment created by HEnvironment::CopyForInlining().
538 output_offset -= kPointerSize;
539 value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
540 output_frame->SetFrameSlot(output_offset, value);
541 if (FLAG_trace_deopt) {
542 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; allocated receiver\n",
543 top_address + output_offset, output_offset, value);
544 }
545
546 ASSERT(0 == output_offset);
547
548 Builtins* builtins = isolate_->builtins();
549 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
550 uint32_t pc = reinterpret_cast<uint32_t>(
551 construct_stub->instruction_start() +
552 isolate_->heap()->construct_stub_deopt_pc_offset()->value());
553 output_frame->SetPc(pc);
554}
555
556
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000557// This code is very similar to ia32/arm code, but relies on register names
558// (fp, sp) and how the frame is laid out.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000559void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
560 int frame_index) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000561 // Read the ast node id, function, and frame height for this output frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000562 int node_id = iterator->Next();
563 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
564 unsigned height = iterator->Next();
565 unsigned height_in_bytes = height * kPointerSize;
566 if (FLAG_trace_deopt) {
567 PrintF(" translating ");
568 function->PrintName();
569 PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes);
570 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000571
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000572 // The 'fixed' part of the frame consists of the incoming parameters and
573 // the part described by JavaScriptFrameConstants.
574 unsigned fixed_frame_size = ComputeFixedSize(function);
575 unsigned input_frame_size = input_->GetFrameSize();
576 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
577
578 // Allocate and store the output frame description.
579 FrameDescription* output_frame =
580 new(output_frame_size) FrameDescription(output_frame_size, function);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000581 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000582
583 bool is_bottommost = (0 == frame_index);
584 bool is_topmost = (output_count_ - 1 == frame_index);
585 ASSERT(frame_index >= 0 && frame_index < output_count_);
586 ASSERT(output_[frame_index] == NULL);
587 output_[frame_index] = output_frame;
588
589 // The top address for the bottommost output frame can be computed from
590 // the input frame pointer and the output frame's height. For all
591 // subsequent output frames, it can be computed from the previous one's
592 // top address and the current frame's size.
593 uint32_t top_address;
594 if (is_bottommost) {
595 // 2 = context and function in the frame.
596 top_address =
597 input_->GetRegister(fp.code()) - (2 * kPointerSize) - height_in_bytes;
598 } else {
599 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
600 }
601 output_frame->SetTop(top_address);
602
603 // Compute the incoming parameter translation.
604 int parameter_count = function->shared()->formal_parameter_count() + 1;
605 unsigned output_offset = output_frame_size;
606 unsigned input_offset = input_frame_size;
607 for (int i = 0; i < parameter_count; ++i) {
608 output_offset -= kPointerSize;
609 DoTranslateCommand(iterator, frame_index, output_offset);
610 }
611 input_offset -= (parameter_count * kPointerSize);
612
613 // There are no translation commands for the caller's pc and fp, the
614 // context, and the function. Synthesize their values and set them up
615 // explicitly.
616 //
617 // The caller's pc for the bottommost output frame is the same as in the
618 // input frame. For all subsequent output frames, it can be read from the
619 // previous one. This frame's pc can be computed from the non-optimized
620 // function code and AST id of the bailout.
621 output_offset -= kPointerSize;
622 input_offset -= kPointerSize;
623 intptr_t value;
624 if (is_bottommost) {
625 value = input_->GetFrameSlot(input_offset);
626 } else {
627 value = output_[frame_index - 1]->GetPc();
628 }
629 output_frame->SetFrameSlot(output_offset, value);
630 if (FLAG_trace_deopt) {
631 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
632 top_address + output_offset, output_offset, value);
633 }
634
635 // The caller's frame pointer for the bottommost output frame is the same
636 // as in the input frame. For all subsequent output frames, it can be
637 // read from the previous one. Also compute and set this frame's frame
638 // pointer.
639 output_offset -= kPointerSize;
640 input_offset -= kPointerSize;
641 if (is_bottommost) {
642 value = input_->GetFrameSlot(input_offset);
643 } else {
644 value = output_[frame_index - 1]->GetFp();
645 }
646 output_frame->SetFrameSlot(output_offset, value);
647 intptr_t fp_value = top_address + output_offset;
648 ASSERT(!is_bottommost || input_->GetRegister(fp.code()) == fp_value);
649 output_frame->SetFp(fp_value);
650 if (is_topmost) {
651 output_frame->SetRegister(fp.code(), fp_value);
652 }
653 if (FLAG_trace_deopt) {
654 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
655 fp_value, output_offset, value);
656 }
657
658 // For the bottommost output frame the context can be gotten from the input
659 // frame. For all subsequent output frames it can be gotten from the function
660 // so long as we don't inline functions that need local contexts.
661 output_offset -= kPointerSize;
662 input_offset -= kPointerSize;
663 if (is_bottommost) {
664 value = input_->GetFrameSlot(input_offset);
665 } else {
666 value = reinterpret_cast<intptr_t>(function->context());
667 }
668 output_frame->SetFrameSlot(output_offset, value);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000669 output_frame->SetContext(value);
670 if (is_topmost) output_frame->SetRegister(cp.code(), value);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000671 if (FLAG_trace_deopt) {
672 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
673 top_address + output_offset, output_offset, value);
674 }
675
676 // The function was mentioned explicitly in the BEGIN_FRAME.
677 output_offset -= kPointerSize;
678 input_offset -= kPointerSize;
679 value = reinterpret_cast<uint32_t>(function);
680 // The function for the bottommost output frame should also agree with the
681 // input frame.
682 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
683 output_frame->SetFrameSlot(output_offset, value);
684 if (FLAG_trace_deopt) {
685 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
686 top_address + output_offset, output_offset, value);
687 }
688
689 // Translate the rest of the frame.
690 for (unsigned i = 0; i < height; ++i) {
691 output_offset -= kPointerSize;
692 DoTranslateCommand(iterator, frame_index, output_offset);
693 }
694 ASSERT(0 == output_offset);
695
696 // Compute this frame's PC, state, and continuation.
697 Code* non_optimized_code = function->shared()->code();
698 FixedArray* raw_data = non_optimized_code->deoptimization_data();
699 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
700 Address start = non_optimized_code->instruction_start();
701 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
702 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
703 uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset);
704 output_frame->SetPc(pc_value);
705
706 FullCodeGenerator::State state =
707 FullCodeGenerator::StateField::decode(pc_and_state);
708 output_frame->SetState(Smi::FromInt(state));
709
710
711 // Set the continuation for the topmost frame.
712 if (is_topmost && bailout_type_ != DEBUGGER) {
713 Builtins* builtins = isolate_->builtins();
714 Code* continuation = (bailout_type_ == EAGER)
715 ? builtins->builtin(Builtins::kNotifyDeoptimized)
716 : builtins->builtin(Builtins::kNotifyLazyDeoptimized);
717 output_frame->SetContinuation(
718 reinterpret_cast<uint32_t>(continuation->entry()));
719 }
720}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000721
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000722void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000723 // Set the register values. The values are not important as there are no
724 // callee saved registers in JavaScript frames, so all registers are
725 // spilled. Registers fp and sp are set to the correct values though.
726
727 for (int i = 0; i < Register::kNumRegisters; i++) {
728 input_->SetRegister(i, i * 4);
729 }
730 input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
731 input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
732 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
733 input_->SetDoubleRegister(i, 0.0);
734 }
735
736 // Fill the frame content from the actual data on the frame.
737 for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
738 input_->SetFrameSlot(i, Memory::uint32_at(tos + i));
739 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000740}
741
742
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000743#define __ masm()->
744
745
746// This code tries to be close to ia32 code so that any changes can be
747// easily ported.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000748void Deoptimizer::EntryGenerator::Generate() {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000749 GeneratePrologue();
750
751 Isolate* isolate = masm()->isolate();
752
753 CpuFeatures::Scope scope(FPU);
754 // Unlike on ARM we don't save all the registers, just the useful ones.
755 // For the rest, there are gaps on the stack, so the offsets remain the same.
756 const int kNumberOfRegisters = Register::kNumRegisters;
757
758 RegList restored_regs = kJSCallerSaved | kCalleeSaved;
759 RegList saved_regs = restored_regs | sp.bit() | ra.bit();
760
761 const int kDoubleRegsSize =
762 kDoubleSize * FPURegister::kNumAllocatableRegisters;
763
764 // Save all FPU registers before messing with them.
765 __ Subu(sp, sp, Operand(kDoubleRegsSize));
766 for (int i = 0; i < FPURegister::kNumAllocatableRegisters; ++i) {
767 FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
768 int offset = i * kDoubleSize;
769 __ sdc1(fpu_reg, MemOperand(sp, offset));
770 }
771
772 // Push saved_regs (needed to populate FrameDescription::registers_).
773 // Leave gaps for other registers.
774 __ Subu(sp, sp, kNumberOfRegisters * kPointerSize);
775 for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) {
776 if ((saved_regs & (1 << i)) != 0) {
777 __ sw(ToRegister(i), MemOperand(sp, kPointerSize * i));
778 }
779 }
780
781 const int kSavedRegistersAreaSize =
782 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
783
784 // Get the bailout id from the stack.
785 __ lw(a2, MemOperand(sp, kSavedRegistersAreaSize));
786
787 // Get the address of the location in the code object if possible (a3) (return
788 // address for lazy deoptimization) and compute the fp-to-sp delta in
789 // register t0.
790 if (type() == EAGER) {
791 __ mov(a3, zero_reg);
792 // Correct one word for bailout id.
793 __ Addu(t0, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
794 } else if (type() == OSR) {
795 __ mov(a3, ra);
796 // Correct one word for bailout id.
797 __ Addu(t0, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
798 } else {
799 __ mov(a3, ra);
800 // Correct two words for bailout id and return address.
801 __ Addu(t0, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
802 }
803
804 __ Subu(t0, fp, t0);
805
806 // Allocate a new deoptimizer object.
807 // Pass four arguments in a0 to a3 and fifth & sixth arguments on stack.
808 __ PrepareCallCFunction(6, t1);
809 __ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
810 __ li(a1, Operand(type())); // bailout type,
811 // a2: bailout id already loaded.
812 // a3: code address or 0 already loaded.
813 __ sw(t0, CFunctionArgumentOperand(5)); // Fp-to-sp delta.
814 __ li(t1, Operand(ExternalReference::isolate_address()));
815 __ sw(t1, CFunctionArgumentOperand(6)); // Isolate.
816 // Call Deoptimizer::New().
817 {
818 AllowExternalCallThatCantCauseGC scope(masm());
819 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 6);
820 }
821
822 // Preserve "deoptimizer" object in register v0 and get the input
823 // frame descriptor pointer to a1 (deoptimizer->input_);
824 // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below.
825 __ mov(a0, v0);
826 __ lw(a1, MemOperand(v0, Deoptimizer::input_offset()));
827
828 // Copy core registers into FrameDescription::registers_[kNumRegisters].
829 ASSERT(Register::kNumRegisters == kNumberOfRegisters);
830 for (int i = 0; i < kNumberOfRegisters; i++) {
831 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
832 if ((saved_regs & (1 << i)) != 0) {
833 __ lw(a2, MemOperand(sp, i * kPointerSize));
834 __ sw(a2, MemOperand(a1, offset));
835 } else if (FLAG_debug_code) {
836 __ li(a2, kDebugZapValue);
837 __ sw(a2, MemOperand(a1, offset));
838 }
839 }
840
841 // Copy FPU registers to
842 // double_registers_[DoubleRegister::kNumAllocatableRegisters]
843 int double_regs_offset = FrameDescription::double_registers_offset();
844 for (int i = 0; i < FPURegister::kNumAllocatableRegisters; ++i) {
845 int dst_offset = i * kDoubleSize + double_regs_offset;
846 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
847 __ ldc1(f0, MemOperand(sp, src_offset));
848 __ sdc1(f0, MemOperand(a1, dst_offset));
849 }
850
851 // Remove the bailout id, eventually return address, and the saved registers
852 // from the stack.
853 if (type() == EAGER || type() == OSR) {
854 __ Addu(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
855 } else {
856 __ Addu(sp, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
857 }
858
859 // Compute a pointer to the unwinding limit in register a2; that is
860 // the first stack slot not part of the input frame.
861 __ lw(a2, MemOperand(a1, FrameDescription::frame_size_offset()));
862 __ Addu(a2, a2, sp);
863
864 // Unwind the stack down to - but not including - the unwinding
865 // limit and copy the contents of the activation frame to the input
866 // frame description.
867 __ Addu(a3, a1, Operand(FrameDescription::frame_content_offset()));
868 Label pop_loop;
869 __ bind(&pop_loop);
870 __ pop(t0);
871 __ sw(t0, MemOperand(a3, 0));
872 __ Branch(USE_DELAY_SLOT, &pop_loop, ne, a2, Operand(sp));
873 __ addiu(a3, a3, sizeof(uint32_t)); // In delay slot.
874
875 // Compute the output frame in the deoptimizer.
876 __ push(a0); // Preserve deoptimizer object across call.
877 // a0: deoptimizer object; a1: scratch.
878 __ PrepareCallCFunction(1, a1);
879 // Call Deoptimizer::ComputeOutputFrames().
880 {
881 AllowExternalCallThatCantCauseGC scope(masm());
882 __ CallCFunction(
883 ExternalReference::compute_output_frames_function(isolate), 1);
884 }
885 __ pop(a0); // Restore deoptimizer object (class Deoptimizer).
886
887 // Replace the current (input) frame with the output frames.
888 Label outer_push_loop, inner_push_loop;
889 // Outer loop state: a0 = current "FrameDescription** output_",
890 // a1 = one past the last FrameDescription**.
891 __ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset()));
892 __ lw(a0, MemOperand(a0, Deoptimizer::output_offset())); // a0 is output_.
893 __ sll(a1, a1, kPointerSizeLog2); // Count to offset.
894 __ addu(a1, a0, a1); // a1 = one past the last FrameDescription**.
895 __ bind(&outer_push_loop);
896 // Inner loop state: a2 = current FrameDescription*, a3 = loop index.
897 __ lw(a2, MemOperand(a0, 0)); // output_[ix]
898 __ lw(a3, MemOperand(a2, FrameDescription::frame_size_offset()));
899 __ bind(&inner_push_loop);
900 __ Subu(a3, a3, Operand(sizeof(uint32_t)));
901 __ Addu(t2, a2, Operand(a3));
902 __ lw(t3, MemOperand(t2, FrameDescription::frame_content_offset()));
903 __ push(t3);
904 __ Branch(&inner_push_loop, ne, a3, Operand(zero_reg));
905
906 __ Addu(a0, a0, Operand(kPointerSize));
907 __ Branch(&outer_push_loop, lt, a0, Operand(a1));
908
909
910 // Push state, pc, and continuation from the last output frame.
911 if (type() != OSR) {
912 __ lw(t2, MemOperand(a2, FrameDescription::state_offset()));
913 __ push(t2);
914 }
915
916 __ lw(t2, MemOperand(a2, FrameDescription::pc_offset()));
917 __ push(t2);
918 __ lw(t2, MemOperand(a2, FrameDescription::continuation_offset()));
919 __ push(t2);
920
921
922 // Technically restoring 'at' should work unless zero_reg is also restored
923 // but it's safer to check for this.
924 ASSERT(!(at.bit() & restored_regs));
925 // Restore the registers from the last output frame.
926 __ mov(at, a2);
927 for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
928 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
929 if ((restored_regs & (1 << i)) != 0) {
930 __ lw(ToRegister(i), MemOperand(at, offset));
931 }
932 }
933
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000934 __ InitializeRootRegister();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000935
936 __ pop(at); // Get continuation, leave pc on stack.
937 __ pop(ra);
938 __ Jump(at);
939 __ stop("Unreachable.");
lrn@chromium.org7516f052011-03-30 08:52:27 +0000940}
941
942
yangguo@chromium.org56454712012-02-16 15:33:53 +0000943// Maximum size of a table entry generated below.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000944const int Deoptimizer::table_entry_size_ = 9 * Assembler::kInstrSize;
yangguo@chromium.org56454712012-02-16 15:33:53 +0000945
lrn@chromium.org7516f052011-03-30 08:52:27 +0000946void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000947 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm());
948
949 // Create a sequence of deoptimization entries. Note that any
950 // registers may be still live.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000951 Label table_start;
952 __ bind(&table_start);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000953 for (int i = 0; i < count(); i++) {
yangguo@chromium.org56454712012-02-16 15:33:53 +0000954 Label start;
955 __ bind(&start);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000956 if (type() != EAGER) {
957 // Emulate ia32 like call by pushing return address to stack.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000958 __ addiu(sp, sp, -2 * kPointerSize);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000959 __ sw(ra, MemOperand(sp, 1 * kPointerSize));
960 } else {
961 __ addiu(sp, sp, -1 * kPointerSize);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000962 }
yangguo@chromium.org56454712012-02-16 15:33:53 +0000963 // Jump over the remaining deopt entries (including this one).
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000964 // This code is always reached by calling Jump, which puts the target (label
965 // start) into t9.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000966 const int remaining_entries = (count() - i) * table_entry_size_;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000967 __ Addu(t9, t9, remaining_entries);
968 // 'at' was clobbered so we can only load the current entry value here.
969 __ li(at, i);
970 __ jr(t9); // Expose delay slot.
971 __ sw(at, MemOperand(sp, 0 * kPointerSize)); // In the delay slot.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000972
973 // Pad the rest of the code.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000974 while (table_entry_size_ > (masm()->SizeOfCodeGeneratedSince(&start))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000975 __ nop();
976 }
977
yangguo@chromium.org56454712012-02-16 15:33:53 +0000978 ASSERT_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000979 }
yangguo@chromium.org56454712012-02-16 15:33:53 +0000980
981 ASSERT_EQ(masm()->SizeOfCodeGeneratedSince(&table_start),
982 count() * table_entry_size_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000983}
984
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000985#undef __
986
lrn@chromium.org7516f052011-03-30 08:52:27 +0000987
988} } // namespace v8::internal