blob: cb24b10e4bedcdb7035d83764caf093b73359d30 [file] [log] [blame]
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "codegen.h"
31#include "deoptimizer.h"
32#include "disasm.h"
33#include "full-codegen.h"
34#include "global-handles.h"
35#include "macro-assembler.h"
36#include "prettyprinter.h"
37
38
39namespace v8 {
40namespace internal {
41
Steve Block44f0eee2011-05-26 01:26:41 +010042DeoptimizerData::DeoptimizerData() {
43 eager_deoptimization_entry_code_ = NULL;
44 lazy_deoptimization_entry_code_ = NULL;
45 current_ = NULL;
46 deoptimizing_code_list_ = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000047#ifdef ENABLE_DEBUGGER_SUPPORT
48 deoptimized_frame_info_ = NULL;
49#endif
Steve Block44f0eee2011-05-26 01:26:41 +010050}
Ben Murdochb0fe1622011-05-05 13:52:32 +010051
52
Steve Block44f0eee2011-05-26 01:26:41 +010053DeoptimizerData::~DeoptimizerData() {
54 if (eager_deoptimization_entry_code_ != NULL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000055 Isolate::Current()->memory_allocator()->Free(
56 eager_deoptimization_entry_code_);
Steve Block44f0eee2011-05-26 01:26:41 +010057 eager_deoptimization_entry_code_ = NULL;
58 }
59 if (lazy_deoptimization_entry_code_ != NULL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000060 Isolate::Current()->memory_allocator()->Free(
61 lazy_deoptimization_entry_code_);
Steve Block44f0eee2011-05-26 01:26:41 +010062 lazy_deoptimization_entry_code_ = NULL;
63 }
64}
65
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000066
67#ifdef ENABLE_DEBUGGER_SUPPORT
68void DeoptimizerData::Iterate(ObjectVisitor* v) {
69 if (deoptimized_frame_info_ != NULL) {
70 deoptimized_frame_info_->Iterate(v);
71 }
72}
73#endif
74
75
Ben Murdoch592a9fc2012-03-05 11:04:45 +000076// We rely on this function not causing a GC. It is called from generated code
77// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +010078Deoptimizer* Deoptimizer::New(JSFunction* function,
79 BailoutType type,
80 unsigned bailout_id,
81 Address from,
Steve Block44f0eee2011-05-26 01:26:41 +010082 int fp_to_sp_delta,
83 Isolate* isolate) {
84 ASSERT(isolate == Isolate::Current());
85 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
86 function,
87 type,
88 bailout_id,
89 from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000090 fp_to_sp_delta,
91 NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010092 ASSERT(isolate->deoptimizer_data()->current_ == NULL);
93 isolate->deoptimizer_data()->current_ = deoptimizer;
Ben Murdochb0fe1622011-05-05 13:52:32 +010094 return deoptimizer;
95}
96
97
Steve Block44f0eee2011-05-26 01:26:41 +010098Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
99 ASSERT(isolate == Isolate::Current());
100 Deoptimizer* result = isolate->deoptimizer_data()->current_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100101 ASSERT(result != NULL);
102 result->DeleteFrameDescriptions();
Steve Block44f0eee2011-05-26 01:26:41 +0100103 isolate->deoptimizer_data()->current_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100104 return result;
105}
106
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000107#ifdef ENABLE_DEBUGGER_SUPPORT
108DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
109 JavaScriptFrame* frame,
110 int frame_index,
111 Isolate* isolate) {
112 ASSERT(isolate == Isolate::Current());
113 ASSERT(frame->is_optimized());
114 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
115
116 // Get the function and code from the frame.
117 JSFunction* function = JSFunction::cast(frame->function());
118 Code* code = frame->LookupCode();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000119
120 // Locate the deoptimization point in the code. As we are at a call the
121 // return address must be at a place in the code with deoptimization support.
Ben Murdoch2b4ba112012-01-20 14:57:15 +0000122 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
123 int deoptimization_index = safepoint_entry.deoptimization_index();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000124 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
125
126 // Always use the actual stack slots when calculating the fp to sp
127 // delta adding two for the function and context.
128 unsigned stack_slots = code->stack_slots();
129 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
130
131 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
132 function,
133 Deoptimizer::DEBUGGER,
134 deoptimization_index,
135 frame->pc(),
136 fp_to_sp_delta,
137 code);
138 Address tos = frame->fp() - fp_to_sp_delta;
139 deoptimizer->FillInputFrame(tos, frame);
140
141 // Calculate the output frames.
142 Deoptimizer::ComputeOutputFrames(deoptimizer);
143
144 // Create the GC safe output frame information and register it for GC
145 // handling.
146 ASSERT_LT(frame_index, deoptimizer->output_count());
147 DeoptimizedFrameInfo* info =
148 new DeoptimizedFrameInfo(deoptimizer, frame_index);
149 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
150
151 // Get the "simulated" top and size for the requested frame.
152 Address top =
153 reinterpret_cast<Address>(deoptimizer->output_[frame_index]->GetTop());
154 uint32_t size = deoptimizer->output_[frame_index]->GetFrameSize();
155
156 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
157 deoptimizer->DeleteFrameDescriptions();
158
159 // Allocate a heap number for the doubles belonging to this frame.
160 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
161 top, size, info);
162
163 // Finished using the deoptimizer instance.
164 delete deoptimizer;
165
166 return info;
167}
168
169
170void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
171 Isolate* isolate) {
172 ASSERT(isolate == Isolate::Current());
173 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
174 delete info;
175 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
176}
177#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100178
179void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
180 int count,
181 BailoutType type) {
182 TableEntryGenerator generator(masm, type, count);
183 generator.Generate();
184}
185
186
187class DeoptimizingVisitor : public OptimizedFunctionVisitor {
188 public:
189 virtual void EnterContext(Context* context) {
190 if (FLAG_trace_deopt) {
191 PrintF("[deoptimize context: %" V8PRIxPTR "]\n",
192 reinterpret_cast<intptr_t>(context));
193 }
194 }
195
196 virtual void VisitFunction(JSFunction* function) {
197 Deoptimizer::DeoptimizeFunction(function);
198 }
199
200 virtual void LeaveContext(Context* context) {
201 context->ClearOptimizedFunctions();
202 }
203};
204
205
206void Deoptimizer::DeoptimizeAll() {
207 AssertNoAllocation no_allocation;
208
209 if (FLAG_trace_deopt) {
210 PrintF("[deoptimize all contexts]\n");
211 }
212
213 DeoptimizingVisitor visitor;
214 VisitAllOptimizedFunctions(&visitor);
215}
216
217
218void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
219 AssertNoAllocation no_allocation;
220
221 DeoptimizingVisitor visitor;
222 VisitAllOptimizedFunctionsForGlobalObject(object, &visitor);
223}
224
225
226void Deoptimizer::VisitAllOptimizedFunctionsForContext(
227 Context* context, OptimizedFunctionVisitor* visitor) {
228 AssertNoAllocation no_allocation;
229
230 ASSERT(context->IsGlobalContext());
231
232 visitor->EnterContext(context);
233 // Run through the list of optimized functions and deoptimize them.
234 Object* element = context->OptimizedFunctionsListHead();
235 while (!element->IsUndefined()) {
236 JSFunction* element_function = JSFunction::cast(element);
237 // Get the next link before deoptimizing as deoptimizing will clear the
238 // next link.
239 element = element_function->next_function_link();
240 visitor->VisitFunction(element_function);
241 }
242 visitor->LeaveContext(context);
243}
244
245
246void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
247 JSObject* object, OptimizedFunctionVisitor* visitor) {
248 AssertNoAllocation no_allocation;
249
250 if (object->IsJSGlobalProxy()) {
251 Object* proto = object->GetPrototype();
252 ASSERT(proto->IsJSGlobalObject());
253 VisitAllOptimizedFunctionsForContext(
254 GlobalObject::cast(proto)->global_context(), visitor);
255 } else if (object->IsGlobalObject()) {
256 VisitAllOptimizedFunctionsForContext(
257 GlobalObject::cast(object)->global_context(), visitor);
258 }
259}
260
261
262void Deoptimizer::VisitAllOptimizedFunctions(
263 OptimizedFunctionVisitor* visitor) {
264 AssertNoAllocation no_allocation;
265
266 // Run through the list of all global contexts and deoptimize.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000267 Object* context = Isolate::Current()->heap()->global_contexts_list();
268 while (!context->IsUndefined()) {
269 // GC can happen when the context is not fully initialized,
270 // so the global field of the context can be undefined.
271 Object* global = Context::cast(context)->get(Context::GLOBAL_INDEX);
272 if (!global->IsUndefined()) {
273 VisitAllOptimizedFunctionsForGlobalObject(JSObject::cast(global),
274 visitor);
275 }
276 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100277 }
278}
279
280
281void Deoptimizer::HandleWeakDeoptimizedCode(
282 v8::Persistent<v8::Value> obj, void* data) {
283 DeoptimizingCodeListNode* node =
284 reinterpret_cast<DeoptimizingCodeListNode*>(data);
285 RemoveDeoptimizingCode(*node->code());
286#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100287 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100288 while (node != NULL) {
289 ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
290 node = node->next();
291 }
292#endif
293}
294
295
Ben Murdoch8b112d22011-06-08 16:22:53 +0100296void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100297 deoptimizer->DoComputeOutputFrames();
298}
299
300
Steve Block44f0eee2011-05-26 01:26:41 +0100301Deoptimizer::Deoptimizer(Isolate* isolate,
302 JSFunction* function,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100303 BailoutType type,
304 unsigned bailout_id,
305 Address from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000306 int fp_to_sp_delta,
307 Code* optimized_code)
Steve Block44f0eee2011-05-26 01:26:41 +0100308 : isolate_(isolate),
309 function_(function),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100310 bailout_id_(bailout_id),
311 bailout_type_(type),
312 from_(from),
313 fp_to_sp_delta_(fp_to_sp_delta),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000314 input_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100315 output_count_(0),
316 output_(NULL),
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000317 frame_alignment_marker_(isolate->heap()->frame_alignment_marker()),
318 has_alignment_padding_(0),
Ben Murdoch8b112d22011-06-08 16:22:53 +0100319 deferred_heap_numbers_(0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100320 if (FLAG_trace_deopt && type != OSR) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000321 if (type == DEBUGGER) {
322 PrintF("**** DEOPT FOR DEBUGGER: ");
323 } else {
324 PrintF("**** DEOPT: ");
325 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100326 function->PrintName();
327 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
328 bailout_id,
329 reinterpret_cast<intptr_t>(from),
330 fp_to_sp_delta - (2 * kPointerSize));
331 } else if (FLAG_trace_osr && type == OSR) {
332 PrintF("**** OSR: ");
333 function->PrintName();
334 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
335 bailout_id,
336 reinterpret_cast<intptr_t>(from),
337 fp_to_sp_delta - (2 * kPointerSize));
338 }
339 // Find the optimized code.
340 if (type == EAGER) {
341 ASSERT(from == NULL);
342 optimized_code_ = function_->code();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000343 if (FLAG_trace_deopt && FLAG_code_comments) {
344 // Print instruction associated with this bailout.
345 const char* last_comment = NULL;
346 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
347 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
348 for (RelocIterator it(optimized_code_, mask); !it.done(); it.next()) {
349 RelocInfo* info = it.rinfo();
350 if (info->rmode() == RelocInfo::COMMENT) {
351 last_comment = reinterpret_cast<const char*>(info->data());
352 }
353 if (info->rmode() == RelocInfo::RUNTIME_ENTRY) {
354 unsigned id = Deoptimizer::GetDeoptimizationId(
355 info->target_address(), Deoptimizer::EAGER);
356 if (id == bailout_id && last_comment != NULL) {
357 PrintF(" %s\n", last_comment);
358 break;
359 }
360 }
361 }
362 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100363 } else if (type == LAZY) {
364 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
365 ASSERT(optimized_code_ != NULL);
366 } else if (type == OSR) {
367 // The function has already been optimized and we're transitioning
368 // from the unoptimized shared version to the optimized one in the
369 // function. The return address (from) points to unoptimized code.
370 optimized_code_ = function_->code();
371 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
372 ASSERT(!optimized_code_->contains(from));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000373 } else if (type == DEBUGGER) {
374 optimized_code_ = optimized_code;
375 ASSERT(optimized_code_->contains(from));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100376 }
Steve Block44f0eee2011-05-26 01:26:41 +0100377 ASSERT(HEAP->allow_allocation(false));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100378 unsigned size = ComputeInputFrameSize();
379 input_ = new(size) FrameDescription(size, function);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000380#ifdef DEBUG
381 input_->SetKind(Code::OPTIMIZED_FUNCTION);
382#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100383}
384
385
386Deoptimizer::~Deoptimizer() {
387 ASSERT(input_ == NULL && output_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100388}
389
390
391void Deoptimizer::DeleteFrameDescriptions() {
392 delete input_;
393 for (int i = 0; i < output_count_; ++i) {
394 if (output_[i] != input_) delete output_[i];
395 }
396 delete[] output_;
397 input_ = NULL;
398 output_ = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100399 ASSERT(!HEAP->allow_allocation(true));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100400}
401
402
403Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
404 ASSERT(id >= 0);
405 if (id >= kNumberOfEntries) return NULL;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000406 MemoryChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100407 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100408 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100409 if (data->eager_deoptimization_entry_code_ == NULL) {
410 data->eager_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100411 }
Steve Block44f0eee2011-05-26 01:26:41 +0100412 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100413 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100414 if (data->lazy_deoptimization_entry_code_ == NULL) {
415 data->lazy_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100416 }
Steve Block44f0eee2011-05-26 01:26:41 +0100417 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100418 }
419 return
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000420 static_cast<Address>(base->area_start()) + (id * table_entry_size_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100421}
422
423
424int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000425 MemoryChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100426 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100427 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100428 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100429 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100430 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100431 }
432 if (base == NULL ||
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000433 addr < base->area_start() ||
434 addr >= base->area_start() +
Ben Murdochb0fe1622011-05-05 13:52:32 +0100435 (kNumberOfEntries * table_entry_size_)) {
436 return kNotDeoptimizationEntry;
437 }
438 ASSERT_EQ(0,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000439 static_cast<int>(addr - base->area_start()) % table_entry_size_);
440 return static_cast<int>(addr - base->area_start()) / table_entry_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100441}
442
443
Steve Block9fac8402011-05-12 15:51:54 +0100444int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
445 unsigned id,
446 SharedFunctionInfo* shared) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100447 // TODO(kasperl): For now, we do a simple linear search for the PC
448 // offset associated with the given node id. This should probably be
449 // changed to a binary search.
450 int length = data->DeoptPoints();
451 Smi* smi_id = Smi::FromInt(id);
452 for (int i = 0; i < length; i++) {
453 if (data->AstId(i) == smi_id) {
454 return data->PcAndState(i)->value();
455 }
456 }
457 PrintF("[couldn't find pc offset for node=%u]\n", id);
458 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
459 // Print the source code if available.
460 HeapStringAllocator string_allocator;
461 StringStream stream(&string_allocator);
462 shared->SourceCodePrint(&stream, -1);
463 PrintF("[source:\n%s\n]", *stream.ToCString());
464
465 UNREACHABLE();
466 return -1;
467}
468
469
Steve Block44f0eee2011-05-26 01:26:41 +0100470int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100471 int length = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100472 DeoptimizingCodeListNode* node =
473 isolate->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100474 while (node != NULL) {
475 length++;
476 node = node->next();
477 }
478 return length;
479}
480
481
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000482// We rely on this function not causing a GC. It is called from generated code
483// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100484void Deoptimizer::DoComputeOutputFrames() {
485 if (bailout_type_ == OSR) {
486 DoComputeOsrOutputFrame();
487 return;
488 }
489
490 // Print some helpful diagnostic information.
491 int64_t start = OS::Ticks();
492 if (FLAG_trace_deopt) {
493 PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
494 (bailout_type_ == LAZY ? " (lazy)" : ""),
495 reinterpret_cast<intptr_t>(function_));
496 function_->PrintName();
497 PrintF(" @%d]\n", bailout_id_);
498 }
499
500 // Determine basic deoptimization information. The optimized frame is
501 // described by the input data.
502 DeoptimizationInputData* input_data =
503 DeoptimizationInputData::cast(optimized_code_->deoptimization_data());
504 unsigned node_id = input_data->AstId(bailout_id_)->value();
505 ByteArray* translations = input_data->TranslationByteArray();
506 unsigned translation_index =
507 input_data->TranslationIndex(bailout_id_)->value();
508
509 // Do the input frame to output frame(s) translation.
510 TranslationIterator iterator(translations, translation_index);
511 Translation::Opcode opcode =
512 static_cast<Translation::Opcode>(iterator.Next());
513 ASSERT(Translation::BEGIN == opcode);
514 USE(opcode);
515 // Read the number of output frames and allocate an array for their
516 // descriptions.
517 int count = iterator.Next();
518 ASSERT(output_ == NULL);
519 output_ = new FrameDescription*[count];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100520 for (int i = 0; i < count; ++i) {
521 output_[i] = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100522 }
523 output_count_ = count;
524
525 // Translate each output frame.
526 for (int i = 0; i < count; ++i) {
527 DoComputeFrame(&iterator, i);
528 }
529
530 // Print some helpful diagnostic information.
531 if (FLAG_trace_deopt) {
532 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
533 int index = output_count_ - 1; // Index of the topmost frame.
534 JSFunction* function = output_[index]->GetFunction();
535 PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
536 reinterpret_cast<intptr_t>(function));
537 function->PrintName();
538 PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
539 node_id,
540 output_[index]->GetPc(),
541 FullCodeGenerator::State2String(
542 static_cast<FullCodeGenerator::State>(
543 output_[index]->GetState()->value())),
544 ms);
545 }
546}
547
548
Ben Murdoch8b112d22011-06-08 16:22:53 +0100549void Deoptimizer::MaterializeHeapNumbers() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000550 ASSERT_NE(DEBUGGER, bailout_type_);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100551 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
552 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
553 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
554 if (FLAG_trace_deopt) {
555 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
556 reinterpret_cast<void*>(*num),
557 d.value(),
558 d.slot_address());
559 }
560
561 Memory::Object_at(d.slot_address()) = *num;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100562 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100563}
564
565
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000566#ifdef ENABLE_DEBUGGER_SUPPORT
567void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
568 Address top, uint32_t size, DeoptimizedFrameInfo* info) {
569 ASSERT_EQ(DEBUGGER, bailout_type_);
570 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
571 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
572
573 // Check of the heap number to materialize actually belong to the frame
574 // being extracted.
575 Address slot = d.slot_address();
576 if (top <= slot && slot < top + size) {
577 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
578 // Calculate the index with the botton of the expression stack
579 // at index 0, and the fixed part (including incoming arguments)
580 // at negative indexes.
581 int index = static_cast<int>(
582 info->expression_count_ - (slot - top) / kPointerSize - 1);
583 if (FLAG_trace_deopt) {
584 PrintF("Materializing a new heap number %p [%e] in slot %p"
585 "for stack index %d\n",
586 reinterpret_cast<void*>(*num),
587 d.value(),
588 d.slot_address(),
589 index);
590 }
591 if (index >=0) {
592 info->SetExpression(index, *num);
593 } else {
594 // Calculate parameter index subtracting one for the receiver.
595 int parameter_index =
596 index +
597 static_cast<int>(size) / kPointerSize -
598 info->expression_count_ - 1;
599 info->SetParameter(parameter_index, *num);
600 }
601 }
602 }
603}
604#endif
605
606
Ben Murdochb0fe1622011-05-05 13:52:32 +0100607void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
608 int frame_index,
609 unsigned output_offset) {
610 disasm::NameConverter converter;
611 // A GC-safe temporary placeholder that we can put in the output frame.
612 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
613
614 // Ignore commands marked as duplicate and act on the first non-duplicate.
615 Translation::Opcode opcode =
616 static_cast<Translation::Opcode>(iterator->Next());
617 while (opcode == Translation::DUPLICATE) {
618 opcode = static_cast<Translation::Opcode>(iterator->Next());
619 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
620 opcode = static_cast<Translation::Opcode>(iterator->Next());
621 }
622
623 switch (opcode) {
624 case Translation::BEGIN:
625 case Translation::FRAME:
626 case Translation::DUPLICATE:
627 UNREACHABLE();
628 return;
629
630 case Translation::REGISTER: {
631 int input_reg = iterator->Next();
632 intptr_t input_value = input_->GetRegister(input_reg);
633 if (FLAG_trace_deopt) {
634 PrintF(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000635 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100636 output_[frame_index]->GetTop() + output_offset,
637 output_offset,
638 input_value,
639 converter.NameOfCPURegister(input_reg));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000640 reinterpret_cast<Object*>(input_value)->ShortPrint();
641 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100642 }
643 output_[frame_index]->SetFrameSlot(output_offset, input_value);
644 return;
645 }
646
647 case Translation::INT32_REGISTER: {
648 int input_reg = iterator->Next();
649 intptr_t value = input_->GetRegister(input_reg);
650 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100651 if (FLAG_trace_deopt) {
652 PrintF(
653 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
654 output_[frame_index]->GetTop() + output_offset,
655 output_offset,
656 value,
657 converter.NameOfCPURegister(input_reg),
658 is_smi ? "smi" : "heap number");
659 }
660 if (is_smi) {
661 intptr_t tagged_value =
662 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
663 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
664 } else {
665 // We save the untagged value on the side and store a GC-safe
666 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100667 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
668 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100669 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
670 }
671 return;
672 }
673
674 case Translation::DOUBLE_REGISTER: {
675 int input_reg = iterator->Next();
676 double value = input_->GetDoubleRegister(input_reg);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100677 if (FLAG_trace_deopt) {
678 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
679 output_[frame_index]->GetTop() + output_offset,
680 output_offset,
681 value,
682 DoubleRegister::AllocationIndexToString(input_reg));
683 }
684 // We save the untagged value on the side and store a GC-safe
685 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100686 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100687 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
688 return;
689 }
690
691 case Translation::STACK_SLOT: {
692 int input_slot_index = iterator->Next();
693 unsigned input_offset =
694 input_->GetOffsetFromSlotIndex(this, input_slot_index);
695 intptr_t input_value = input_->GetFrameSlot(input_offset);
696 if (FLAG_trace_deopt) {
697 PrintF(" 0x%08" V8PRIxPTR ": ",
698 output_[frame_index]->GetTop() + output_offset);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000699 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100700 output_offset,
701 input_value,
702 input_offset);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000703 reinterpret_cast<Object*>(input_value)->ShortPrint();
704 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100705 }
706 output_[frame_index]->SetFrameSlot(output_offset, input_value);
707 return;
708 }
709
710 case Translation::INT32_STACK_SLOT: {
711 int input_slot_index = iterator->Next();
712 unsigned input_offset =
713 input_->GetOffsetFromSlotIndex(this, input_slot_index);
714 intptr_t value = input_->GetFrameSlot(input_offset);
715 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100716 if (FLAG_trace_deopt) {
717 PrintF(" 0x%08" V8PRIxPTR ": ",
718 output_[frame_index]->GetTop() + output_offset);
719 PrintF("[top + %d] <- %" V8PRIdPTR " ; [esp + %d] (%s)\n",
720 output_offset,
721 value,
722 input_offset,
723 is_smi ? "smi" : "heap number");
724 }
725 if (is_smi) {
726 intptr_t tagged_value =
727 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
728 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
729 } else {
730 // We save the untagged value on the side and store a GC-safe
731 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100732 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
733 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100734 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
735 }
736 return;
737 }
738
739 case Translation::DOUBLE_STACK_SLOT: {
740 int input_slot_index = iterator->Next();
741 unsigned input_offset =
742 input_->GetOffsetFromSlotIndex(this, input_slot_index);
743 double value = input_->GetDoubleFrameSlot(input_offset);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100744 if (FLAG_trace_deopt) {
745 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
746 output_[frame_index]->GetTop() + output_offset,
747 output_offset,
748 value,
749 input_offset);
750 }
751 // We save the untagged value on the side and store a GC-safe
752 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100753 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100754 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
755 return;
756 }
757
758 case Translation::LITERAL: {
759 Object* literal = ComputeLiteral(iterator->Next());
760 if (FLAG_trace_deopt) {
761 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
762 output_[frame_index]->GetTop() + output_offset,
763 output_offset);
764 literal->ShortPrint();
765 PrintF(" ; literal\n");
766 }
767 intptr_t value = reinterpret_cast<intptr_t>(literal);
768 output_[frame_index]->SetFrameSlot(output_offset, value);
769 return;
770 }
771
772 case Translation::ARGUMENTS_OBJECT: {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100773 // Use the arguments marker value as a sentinel and fill in the arguments
774 // object after the deoptimized frame is built.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100775 ASSERT(frame_index == 0); // Only supported for first frame.
776 if (FLAG_trace_deopt) {
777 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
778 output_[frame_index]->GetTop() + output_offset,
779 output_offset);
Steve Block44f0eee2011-05-26 01:26:41 +0100780 isolate_->heap()->arguments_marker()->ShortPrint();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100781 PrintF(" ; arguments object\n");
782 }
Steve Block44f0eee2011-05-26 01:26:41 +0100783 intptr_t value = reinterpret_cast<intptr_t>(
784 isolate_->heap()->arguments_marker());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100785 output_[frame_index]->SetFrameSlot(output_offset, value);
786 return;
787 }
788 }
789}
790
791
792bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
793 int* input_offset) {
794 disasm::NameConverter converter;
795 FrameDescription* output = output_[0];
796
797 // The input values are all part of the unoptimized frame so they
798 // are all tagged pointers.
799 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
800 Object* input_object = reinterpret_cast<Object*>(input_value);
801
802 Translation::Opcode opcode =
803 static_cast<Translation::Opcode>(iterator->Next());
804 bool duplicate = (opcode == Translation::DUPLICATE);
805 if (duplicate) {
806 opcode = static_cast<Translation::Opcode>(iterator->Next());
807 }
808
809 switch (opcode) {
810 case Translation::BEGIN:
811 case Translation::FRAME:
812 case Translation::DUPLICATE:
813 UNREACHABLE(); // Malformed input.
814 return false;
815
816 case Translation::REGISTER: {
817 int output_reg = iterator->Next();
818 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100819 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100820 converter.NameOfCPURegister(output_reg),
821 input_value,
822 *input_offset);
823 }
824 output->SetRegister(output_reg, input_value);
825 break;
826 }
827
828 case Translation::INT32_REGISTER: {
829 // Abort OSR if we don't have a number.
830 if (!input_object->IsNumber()) return false;
831
832 int output_reg = iterator->Next();
833 int int32_value = input_object->IsSmi()
834 ? Smi::cast(input_object)->value()
835 : FastD2I(input_object->Number());
836 // Abort the translation if the conversion lost information.
837 if (!input_object->IsSmi() &&
838 FastI2D(int32_value) != input_object->Number()) {
839 if (FLAG_trace_osr) {
840 PrintF("**** %g could not be converted to int32 ****\n",
841 input_object->Number());
842 }
843 return false;
844 }
845 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100846 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100847 converter.NameOfCPURegister(output_reg),
848 int32_value,
849 *input_offset);
850 }
851 output->SetRegister(output_reg, int32_value);
852 break;
853 }
854
855 case Translation::DOUBLE_REGISTER: {
856 // Abort OSR if we don't have a number.
857 if (!input_object->IsNumber()) return false;
858
859 int output_reg = iterator->Next();
860 double double_value = input_object->Number();
861 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100862 PrintF(" %s <- %g (double) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100863 DoubleRegister::AllocationIndexToString(output_reg),
864 double_value,
865 *input_offset);
866 }
867 output->SetDoubleRegister(output_reg, double_value);
868 break;
869 }
870
871 case Translation::STACK_SLOT: {
872 int output_index = iterator->Next();
873 unsigned output_offset =
874 output->GetOffsetFromSlotIndex(this, output_index);
875 if (FLAG_trace_osr) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000876 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100877 output_offset,
878 input_value,
879 *input_offset);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000880 reinterpret_cast<Object*>(input_value)->ShortPrint();
881 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100882 }
883 output->SetFrameSlot(output_offset, input_value);
884 break;
885 }
886
887 case Translation::INT32_STACK_SLOT: {
888 // Abort OSR if we don't have a number.
889 if (!input_object->IsNumber()) return false;
890
891 int output_index = iterator->Next();
892 unsigned output_offset =
893 output->GetOffsetFromSlotIndex(this, output_index);
894 int int32_value = input_object->IsSmi()
895 ? Smi::cast(input_object)->value()
896 : DoubleToInt32(input_object->Number());
897 // Abort the translation if the conversion lost information.
898 if (!input_object->IsSmi() &&
899 FastI2D(int32_value) != input_object->Number()) {
900 if (FLAG_trace_osr) {
901 PrintF("**** %g could not be converted to int32 ****\n",
902 input_object->Number());
903 }
904 return false;
905 }
906 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100907 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100908 output_offset,
909 int32_value,
910 *input_offset);
911 }
912 output->SetFrameSlot(output_offset, int32_value);
913 break;
914 }
915
916 case Translation::DOUBLE_STACK_SLOT: {
917 static const int kLowerOffset = 0 * kPointerSize;
918 static const int kUpperOffset = 1 * kPointerSize;
919
920 // Abort OSR if we don't have a number.
921 if (!input_object->IsNumber()) return false;
922
923 int output_index = iterator->Next();
924 unsigned output_offset =
925 output->GetOffsetFromSlotIndex(this, output_index);
926 double double_value = input_object->Number();
927 uint64_t int_value = BitCast<uint64_t, double>(double_value);
928 int32_t lower = static_cast<int32_t>(int_value);
929 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
930 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100931 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100932 output_offset + kUpperOffset,
933 upper,
934 double_value,
935 *input_offset);
Steve Block1e0659c2011-05-24 12:43:12 +0100936 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100937 output_offset + kLowerOffset,
938 lower,
939 double_value,
940 *input_offset);
941 }
942 output->SetFrameSlot(output_offset + kLowerOffset, lower);
943 output->SetFrameSlot(output_offset + kUpperOffset, upper);
944 break;
945 }
946
947 case Translation::LITERAL: {
948 // Just ignore non-materialized literals.
949 iterator->Next();
950 break;
951 }
952
953 case Translation::ARGUMENTS_OBJECT: {
954 // Optimized code assumes that the argument object has not been
955 // materialized and so bypasses it when doing arguments access.
956 // We should have bailed out before starting the frame
957 // translation.
958 UNREACHABLE();
959 return false;
960 }
961 }
962
963 if (!duplicate) *input_offset -= kPointerSize;
964 return true;
965}
966
967
Steve Block1e0659c2011-05-24 12:43:12 +0100968void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
969 Code* check_code,
970 Code* replacement_code) {
971 // Iterate over the stack check table and patch every stack check
972 // call to an unconditional call to the replacement code.
973 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
974 Address stack_check_cursor = unoptimized_code->instruction_start() +
975 unoptimized_code->stack_check_table_offset();
976 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
977 stack_check_cursor += kIntSize;
978 for (uint32_t i = 0; i < table_length; ++i) {
979 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
980 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000981 PatchStackCheckCodeAt(unoptimized_code,
982 pc_after,
983 check_code,
984 replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +0100985 stack_check_cursor += 2 * kIntSize;
986 }
987}
988
989
990void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
991 Code* check_code,
992 Code* replacement_code) {
993 // Iterate over the stack check table and revert the patched
994 // stack check calls.
995 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
996 Address stack_check_cursor = unoptimized_code->instruction_start() +
997 unoptimized_code->stack_check_table_offset();
998 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
999 stack_check_cursor += kIntSize;
1000 for (uint32_t i = 0; i < table_length; ++i) {
1001 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1002 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001003 RevertStackCheckCodeAt(unoptimized_code,
1004 pc_after,
1005 check_code,
1006 replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +01001007 stack_check_cursor += 2 * kIntSize;
1008 }
1009}
1010
1011
Ben Murdochb0fe1622011-05-05 13:52:32 +01001012unsigned Deoptimizer::ComputeInputFrameSize() const {
1013 unsigned fixed_size = ComputeFixedSize(function_);
1014 // The fp-to-sp delta already takes the context and the function
1015 // into account so we have to avoid double counting them (-2).
1016 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
1017#ifdef DEBUG
1018 if (bailout_type_ == OSR) {
1019 // TODO(kasperl): It would be nice if we could verify that the
1020 // size matches with the stack height we can compute based on the
1021 // environment at the OSR entry. The code for that his built into
1022 // the DoComputeOsrOutputFrame function for now.
1023 } else {
1024 unsigned stack_slots = optimized_code_->stack_slots();
1025 unsigned outgoing_size = ComputeOutgoingArgumentSize();
1026 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
1027 }
1028#endif
1029 return result;
1030}
1031
1032
1033unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
1034 // The fixed part of the frame consists of the return address, frame
1035 // pointer, function, context, and all the incoming arguments.
1036 static const unsigned kFixedSlotSize = 4 * kPointerSize;
1037 return ComputeIncomingArgumentSize(function) + kFixedSlotSize;
1038}
1039
1040
1041unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
1042 // The incoming arguments is the values for formal parameters and
1043 // the receiver. Every slot contains a pointer.
1044 unsigned arguments = function->shared()->formal_parameter_count() + 1;
1045 return arguments * kPointerSize;
1046}
1047
1048
1049unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
1050 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1051 optimized_code_->deoptimization_data());
1052 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
1053 return height * kPointerSize;
1054}
1055
1056
1057Object* Deoptimizer::ComputeLiteral(int index) const {
1058 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1059 optimized_code_->deoptimization_data());
1060 FixedArray* literals = data->LiteralArray();
1061 return literals->get(index);
1062}
1063
1064
Ben Murdoch8b112d22011-06-08 16:22:53 +01001065void Deoptimizer::AddDoubleValue(intptr_t slot_address,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001066 double value) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001067 HeapNumberMaterializationDescriptor value_desc(
1068 reinterpret_cast<Address>(slot_address), value);
1069 deferred_heap_numbers_.Add(value_desc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001070}
1071
1072
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001073MemoryChunk* Deoptimizer::CreateCode(BailoutType type) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001074 // We cannot run this if the serializer is enabled because this will
1075 // cause us to emit relocation information for the external
1076 // references. This is fine because the deoptimizer's code section
1077 // isn't meant to be serialized at all.
1078 ASSERT(!Serializer::enabled());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001079
Ben Murdoch8b112d22011-06-08 16:22:53 +01001080 MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
Steve Block44f0eee2011-05-26 01:26:41 +01001081 masm.set_emit_debug_code(false);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001082 GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
1083 CodeDesc desc;
1084 masm.GetCode(&desc);
1085 ASSERT(desc.reloc_size == 0);
1086
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001087 MemoryChunk* chunk =
1088 Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
1089 EXECUTABLE,
1090 NULL);
1091 ASSERT(chunk->area_size() >= desc.instr_size);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001092 if (chunk == NULL) {
1093 V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
1094 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001095 memcpy(chunk->area_start(), desc.buffer, desc.instr_size);
1096 CPU::FlushICache(chunk->area_start(), desc.instr_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001097 return chunk;
1098}
1099
1100
1101Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001102 DeoptimizingCodeListNode* node =
1103 Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001104 while (node != NULL) {
1105 if (node->code()->contains(addr)) return *node->code();
1106 node = node->next();
1107 }
1108 return NULL;
1109}
1110
1111
1112void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
Steve Block44f0eee2011-05-26 01:26:41 +01001113 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
1114 ASSERT(data->deoptimizing_code_list_ != NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001115 // Run through the code objects to find this one and remove it.
1116 DeoptimizingCodeListNode* prev = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01001117 DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001118 while (current != NULL) {
1119 if (*current->code() == code) {
1120 // Unlink from list. If prev is NULL we are looking at the first element.
1121 if (prev == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001122 data->deoptimizing_code_list_ = current->next();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001123 } else {
1124 prev->set_next(current->next());
1125 }
1126 delete current;
1127 return;
1128 }
1129 // Move to next in list.
1130 prev = current;
1131 current = current->next();
1132 }
1133 // Deoptimizing code is removed through weak callback. Each object is expected
1134 // to be removed once and only once.
1135 UNREACHABLE();
1136}
1137
1138
1139FrameDescription::FrameDescription(uint32_t frame_size,
1140 JSFunction* function)
1141 : frame_size_(frame_size),
1142 function_(function),
1143 top_(kZapUint32),
1144 pc_(kZapUint32),
1145 fp_(kZapUint32) {
1146 // Zap all the registers.
1147 for (int r = 0; r < Register::kNumRegisters; r++) {
1148 SetRegister(r, kZapUint32);
1149 }
1150
1151 // Zap all the slots.
1152 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
1153 SetFrameSlot(o, kZapUint32);
1154 }
1155}
1156
1157
1158unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer,
1159 int slot_index) {
1160 if (slot_index >= 0) {
1161 // Local or spill slots. Skip the fixed part of the frame
1162 // including all arguments.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001163 unsigned base =
1164 GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001165 return base - ((slot_index + 1) * kPointerSize);
1166 } else {
1167 // Incoming parameter.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001168 unsigned base = GetFrameSize() -
1169 deoptimizer->ComputeIncomingArgumentSize(GetFunction());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001170 return base - ((slot_index + 1) * kPointerSize);
1171 }
1172}
1173
1174
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001175int FrameDescription::ComputeParametersCount() {
1176 return function_->shared()->formal_parameter_count();
1177}
1178
1179
1180Object* FrameDescription::GetParameter(Deoptimizer* deoptimizer, int index) {
1181 ASSERT_EQ(Code::FUNCTION, kind_);
1182 ASSERT(index >= 0);
1183 ASSERT(index < ComputeParametersCount());
1184 // The slot indexes for incoming arguments are negative.
1185 unsigned offset = GetOffsetFromSlotIndex(deoptimizer,
1186 index - ComputeParametersCount());
1187 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1188}
1189
1190
1191unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) {
1192 ASSERT_EQ(Code::FUNCTION, kind_);
1193 unsigned size = GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
1194 return size / kPointerSize;
1195}
1196
1197
1198Object* FrameDescription::GetExpression(Deoptimizer* deoptimizer, int index) {
1199 ASSERT_EQ(Code::FUNCTION, kind_);
1200 unsigned offset = GetOffsetFromSlotIndex(deoptimizer, index);
1201 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1202}
1203
1204
Ben Murdochb0fe1622011-05-05 13:52:32 +01001205void TranslationBuffer::Add(int32_t value) {
1206 // Encode the sign bit in the least significant bit.
1207 bool is_negative = (value < 0);
1208 uint32_t bits = ((is_negative ? -value : value) << 1) |
1209 static_cast<int32_t>(is_negative);
1210 // Encode the individual bytes using the least significant bit of
1211 // each byte to indicate whether or not more bytes follow.
1212 do {
1213 uint32_t next = bits >> 7;
1214 contents_.Add(((bits << 1) & 0xFF) | (next != 0));
1215 bits = next;
1216 } while (bits != 0);
1217}
1218
1219
1220int32_t TranslationIterator::Next() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001221 // Run through the bytes until we reach one with a least significant
1222 // bit of zero (marks the end).
1223 uint32_t bits = 0;
1224 for (int i = 0; true; i += 7) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001225 ASSERT(HasNext());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001226 uint8_t next = buffer_->get(index_++);
1227 bits |= (next >> 1) << i;
1228 if ((next & 1) == 0) break;
1229 }
1230 // The bits encode the sign in the least significant bit.
1231 bool is_negative = (bits & 1) == 1;
1232 int32_t result = bits >> 1;
1233 return is_negative ? -result : result;
1234}
1235
1236
1237Handle<ByteArray> TranslationBuffer::CreateByteArray() {
1238 int length = contents_.length();
Steve Block44f0eee2011-05-26 01:26:41 +01001239 Handle<ByteArray> result =
1240 Isolate::Current()->factory()->NewByteArray(length, TENURED);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001241 memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
1242 return result;
1243}
1244
1245
1246void Translation::BeginFrame(int node_id, int literal_id, unsigned height) {
1247 buffer_->Add(FRAME);
1248 buffer_->Add(node_id);
1249 buffer_->Add(literal_id);
1250 buffer_->Add(height);
1251}
1252
1253
1254void Translation::StoreRegister(Register reg) {
1255 buffer_->Add(REGISTER);
1256 buffer_->Add(reg.code());
1257}
1258
1259
1260void Translation::StoreInt32Register(Register reg) {
1261 buffer_->Add(INT32_REGISTER);
1262 buffer_->Add(reg.code());
1263}
1264
1265
1266void Translation::StoreDoubleRegister(DoubleRegister reg) {
1267 buffer_->Add(DOUBLE_REGISTER);
1268 buffer_->Add(DoubleRegister::ToAllocationIndex(reg));
1269}
1270
1271
1272void Translation::StoreStackSlot(int index) {
1273 buffer_->Add(STACK_SLOT);
1274 buffer_->Add(index);
1275}
1276
1277
1278void Translation::StoreInt32StackSlot(int index) {
1279 buffer_->Add(INT32_STACK_SLOT);
1280 buffer_->Add(index);
1281}
1282
1283
1284void Translation::StoreDoubleStackSlot(int index) {
1285 buffer_->Add(DOUBLE_STACK_SLOT);
1286 buffer_->Add(index);
1287}
1288
1289
1290void Translation::StoreLiteral(int literal_id) {
1291 buffer_->Add(LITERAL);
1292 buffer_->Add(literal_id);
1293}
1294
1295
1296void Translation::StoreArgumentsObject() {
1297 buffer_->Add(ARGUMENTS_OBJECT);
1298}
1299
1300
1301void Translation::MarkDuplicate() {
1302 buffer_->Add(DUPLICATE);
1303}
1304
1305
1306int Translation::NumberOfOperandsFor(Opcode opcode) {
1307 switch (opcode) {
1308 case ARGUMENTS_OBJECT:
1309 case DUPLICATE:
1310 return 0;
1311 case BEGIN:
1312 case REGISTER:
1313 case INT32_REGISTER:
1314 case DOUBLE_REGISTER:
1315 case STACK_SLOT:
1316 case INT32_STACK_SLOT:
1317 case DOUBLE_STACK_SLOT:
1318 case LITERAL:
1319 return 1;
1320 case FRAME:
1321 return 3;
1322 }
1323 UNREACHABLE();
1324 return -1;
1325}
1326
1327
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001328#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001329
1330const char* Translation::StringFor(Opcode opcode) {
1331 switch (opcode) {
1332 case BEGIN:
1333 return "BEGIN";
1334 case FRAME:
1335 return "FRAME";
1336 case REGISTER:
1337 return "REGISTER";
1338 case INT32_REGISTER:
1339 return "INT32_REGISTER";
1340 case DOUBLE_REGISTER:
1341 return "DOUBLE_REGISTER";
1342 case STACK_SLOT:
1343 return "STACK_SLOT";
1344 case INT32_STACK_SLOT:
1345 return "INT32_STACK_SLOT";
1346 case DOUBLE_STACK_SLOT:
1347 return "DOUBLE_STACK_SLOT";
1348 case LITERAL:
1349 return "LITERAL";
1350 case ARGUMENTS_OBJECT:
1351 return "ARGUMENTS_OBJECT";
1352 case DUPLICATE:
1353 return "DUPLICATE";
1354 }
1355 UNREACHABLE();
1356 return "";
1357}
1358
1359#endif
1360
1361
1362DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001363 GlobalHandles* global_handles = Isolate::Current()->global_handles();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001364 // Globalize the code object and make it weak.
Steve Block44f0eee2011-05-26 01:26:41 +01001365 code_ = Handle<Code>::cast(global_handles->Create(code));
1366 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
1367 this,
1368 Deoptimizer::HandleWeakDeoptimizedCode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001369}
1370
1371
1372DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
Steve Block44f0eee2011-05-26 01:26:41 +01001373 GlobalHandles* global_handles = Isolate::Current()->global_handles();
1374 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001375}
1376
1377
Ben Murdoch8b112d22011-06-08 16:22:53 +01001378// We can't intermix stack decoding and allocations because
1379// deoptimization infrastracture is not GC safe.
1380// Thus we build a temporary structure in malloced space.
1381SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
1382 DeoptimizationInputData* data,
1383 JavaScriptFrame* frame) {
1384 Translation::Opcode opcode =
1385 static_cast<Translation::Opcode>(iterator->Next());
1386
1387 switch (opcode) {
1388 case Translation::BEGIN:
1389 case Translation::FRAME:
1390 // Peeled off before getting here.
1391 break;
1392
1393 case Translation::ARGUMENTS_OBJECT:
1394 // This can be only emitted for local slots not for argument slots.
1395 break;
1396
1397 case Translation::REGISTER:
1398 case Translation::INT32_REGISTER:
1399 case Translation::DOUBLE_REGISTER:
1400 case Translation::DUPLICATE:
1401 // We are at safepoint which corresponds to call. All registers are
1402 // saved by caller so there would be no live registers at this
1403 // point. Thus these translation commands should not be used.
1404 break;
1405
1406 case Translation::STACK_SLOT: {
1407 int slot_index = iterator->Next();
1408 Address slot_addr = SlotAddress(frame, slot_index);
1409 return SlotRef(slot_addr, SlotRef::TAGGED);
1410 }
1411
1412 case Translation::INT32_STACK_SLOT: {
1413 int slot_index = iterator->Next();
1414 Address slot_addr = SlotAddress(frame, slot_index);
1415 return SlotRef(slot_addr, SlotRef::INT32);
1416 }
1417
1418 case Translation::DOUBLE_STACK_SLOT: {
1419 int slot_index = iterator->Next();
1420 Address slot_addr = SlotAddress(frame, slot_index);
1421 return SlotRef(slot_addr, SlotRef::DOUBLE);
1422 }
1423
1424 case Translation::LITERAL: {
1425 int literal_index = iterator->Next();
1426 return SlotRef(data->LiteralArray()->get(literal_index));
1427 }
1428 }
1429
1430 UNREACHABLE();
1431 return SlotRef();
1432}
1433
1434
1435void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame,
1436 int inlined_frame_index,
1437 Vector<SlotRef>* args_slots) {
1438 AssertNoAllocation no_gc;
1439 int deopt_index = AstNode::kNoNumber;
1440 DeoptimizationInputData* data =
1441 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
1442 TranslationIterator it(data->TranslationByteArray(),
1443 data->TranslationIndex(deopt_index)->value());
1444 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1445 ASSERT(opcode == Translation::BEGIN);
1446 int frame_count = it.Next();
1447 USE(frame_count);
1448 ASSERT(frame_count > inlined_frame_index);
1449 int frames_to_skip = inlined_frame_index;
1450 while (true) {
1451 opcode = static_cast<Translation::Opcode>(it.Next());
1452 // Skip over operands to advance to the next opcode.
1453 it.Skip(Translation::NumberOfOperandsFor(opcode));
1454 if (opcode == Translation::FRAME) {
1455 if (frames_to_skip == 0) {
1456 // We reached the frame corresponding to the inlined function
1457 // in question. Process the translation commands for the
1458 // arguments.
1459 //
1460 // Skip the translation command for the receiver.
1461 it.Skip(Translation::NumberOfOperandsFor(
1462 static_cast<Translation::Opcode>(it.Next())));
1463 // Compute slots for arguments.
1464 for (int i = 0; i < args_slots->length(); ++i) {
1465 (*args_slots)[i] = ComputeSlotForNextArgument(&it, data, frame);
1466 }
1467 return;
1468 }
1469 frames_to_skip--;
1470 }
1471 }
1472
1473 UNREACHABLE();
1474}
1475
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001476#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch8b112d22011-06-08 16:22:53 +01001477
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001478DeoptimizedFrameInfo::DeoptimizedFrameInfo(
1479 Deoptimizer* deoptimizer, int frame_index) {
1480 FrameDescription* output_frame = deoptimizer->output_[frame_index];
1481 SetFunction(output_frame->GetFunction());
1482 expression_count_ = output_frame->GetExpressionCount(deoptimizer);
1483 parameters_count_ = output_frame->ComputeParametersCount();
1484 parameters_ = new Object*[parameters_count_];
1485 for (int i = 0; i < parameters_count_; i++) {
1486 SetParameter(i, output_frame->GetParameter(deoptimizer, i));
1487 }
1488 expression_stack_ = new Object*[expression_count_];
1489 for (int i = 0; i < expression_count_; i++) {
1490 SetExpression(i, output_frame->GetExpression(deoptimizer, i));
1491 }
1492}
1493
1494
1495DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
1496 delete[] expression_stack_;
1497 delete[] parameters_;
1498}
1499
1500void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
1501 v->VisitPointer(BitCast<Object**>(&function_));
1502 v->VisitPointers(parameters_, parameters_ + parameters_count_);
1503 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
1504}
1505
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001506#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001507
Ben Murdochb0fe1622011-05-05 13:52:32 +01001508} } // namespace v8::internal