blob: 0ada28b0155693662b229da9f979588ed396295a [file] [log] [blame]
Ben Murdoch85b71792012-04-11 18:30:58 +01001// 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 Murdoch85b71792012-04-11 18:30:58 +010055 eager_deoptimization_entry_code_->Free(EXECUTABLE);
Steve Block44f0eee2011-05-26 01:26:41 +010056 eager_deoptimization_entry_code_ = NULL;
57 }
58 if (lazy_deoptimization_entry_code_ != NULL) {
Ben Murdoch85b71792012-04-11 18:30:58 +010059 lazy_deoptimization_entry_code_->Free(EXECUTABLE);
Steve Block44f0eee2011-05-26 01:26:41 +010060 lazy_deoptimization_entry_code_ = NULL;
61 }
62}
63
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000064
65#ifdef ENABLE_DEBUGGER_SUPPORT
66void DeoptimizerData::Iterate(ObjectVisitor* v) {
67 if (deoptimized_frame_info_ != NULL) {
68 deoptimized_frame_info_->Iterate(v);
69 }
70}
71#endif
72
73
Ben Murdochb0fe1622011-05-05 13:52:32 +010074Deoptimizer* Deoptimizer::New(JSFunction* function,
75 BailoutType type,
76 unsigned bailout_id,
77 Address from,
Steve Block44f0eee2011-05-26 01:26:41 +010078 int fp_to_sp_delta,
79 Isolate* isolate) {
80 ASSERT(isolate == Isolate::Current());
81 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
82 function,
83 type,
84 bailout_id,
85 from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000086 fp_to_sp_delta,
87 NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010088 ASSERT(isolate->deoptimizer_data()->current_ == NULL);
89 isolate->deoptimizer_data()->current_ = deoptimizer;
Ben Murdochb0fe1622011-05-05 13:52:32 +010090 return deoptimizer;
91}
92
93
Steve Block44f0eee2011-05-26 01:26:41 +010094Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
95 ASSERT(isolate == Isolate::Current());
96 Deoptimizer* result = isolate->deoptimizer_data()->current_;
Ben Murdochb0fe1622011-05-05 13:52:32 +010097 ASSERT(result != NULL);
98 result->DeleteFrameDescriptions();
Steve Block44f0eee2011-05-26 01:26:41 +010099 isolate->deoptimizer_data()->current_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100100 return result;
101}
102
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000103#ifdef ENABLE_DEBUGGER_SUPPORT
104DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
105 JavaScriptFrame* frame,
Ben Murdoch85b71792012-04-11 18:30:58 +0100106 int frame_index,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000107 Isolate* isolate) {
108 ASSERT(isolate == Isolate::Current());
109 ASSERT(frame->is_optimized());
110 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
111
112 // Get the function and code from the frame.
113 JSFunction* function = JSFunction::cast(frame->function());
114 Code* code = frame->LookupCode();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000115
116 // Locate the deoptimization point in the code. As we are at a call the
117 // return address must be at a place in the code with deoptimization support.
Ben Murdoch2b4ba112012-01-20 14:57:15 +0000118 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
119 int deoptimization_index = safepoint_entry.deoptimization_index();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000120 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
121
122 // Always use the actual stack slots when calculating the fp to sp
123 // delta adding two for the function and context.
124 unsigned stack_slots = code->stack_slots();
125 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
126
127 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
128 function,
129 Deoptimizer::DEBUGGER,
130 deoptimization_index,
131 frame->pc(),
132 fp_to_sp_delta,
133 code);
134 Address tos = frame->fp() - fp_to_sp_delta;
135 deoptimizer->FillInputFrame(tos, frame);
136
137 // Calculate the output frames.
138 Deoptimizer::ComputeOutputFrames(deoptimizer);
139
140 // Create the GC safe output frame information and register it for GC
141 // handling.
Ben Murdoch85b71792012-04-11 18:30:58 +0100142 ASSERT_LT(frame_index, deoptimizer->output_count());
143 DeoptimizedFrameInfo* info =
144 new DeoptimizedFrameInfo(deoptimizer, frame_index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000145 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
146
147 // Get the "simulated" top and size for the requested frame.
Ben Murdoch85b71792012-04-11 18:30:58 +0100148 Address top =
149 reinterpret_cast<Address>(deoptimizer->output_[frame_index]->GetTop());
150 uint32_t size = deoptimizer->output_[frame_index]->GetFrameSize();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000151
152 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
153 deoptimizer->DeleteFrameDescriptions();
154
155 // Allocate a heap number for the doubles belonging to this frame.
156 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdoch85b71792012-04-11 18:30:58 +0100157 top, size, info);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000158
159 // Finished using the deoptimizer instance.
160 delete deoptimizer;
161
162 return info;
163}
164
165
166void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
167 Isolate* isolate) {
168 ASSERT(isolate == Isolate::Current());
169 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
170 delete info;
171 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
172}
173#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100174
175void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
176 int count,
177 BailoutType type) {
178 TableEntryGenerator generator(masm, type, count);
179 generator.Generate();
180}
181
182
183class DeoptimizingVisitor : public OptimizedFunctionVisitor {
184 public:
185 virtual void EnterContext(Context* context) {
186 if (FLAG_trace_deopt) {
187 PrintF("[deoptimize context: %" V8PRIxPTR "]\n",
188 reinterpret_cast<intptr_t>(context));
189 }
190 }
191
192 virtual void VisitFunction(JSFunction* function) {
193 Deoptimizer::DeoptimizeFunction(function);
194 }
195
196 virtual void LeaveContext(Context* context) {
197 context->ClearOptimizedFunctions();
198 }
199};
200
201
202void Deoptimizer::DeoptimizeAll() {
203 AssertNoAllocation no_allocation;
204
205 if (FLAG_trace_deopt) {
206 PrintF("[deoptimize all contexts]\n");
207 }
208
209 DeoptimizingVisitor visitor;
210 VisitAllOptimizedFunctions(&visitor);
211}
212
213
214void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
215 AssertNoAllocation no_allocation;
216
217 DeoptimizingVisitor visitor;
218 VisitAllOptimizedFunctionsForGlobalObject(object, &visitor);
219}
220
221
222void Deoptimizer::VisitAllOptimizedFunctionsForContext(
223 Context* context, OptimizedFunctionVisitor* visitor) {
224 AssertNoAllocation no_allocation;
225
226 ASSERT(context->IsGlobalContext());
227
228 visitor->EnterContext(context);
229 // Run through the list of optimized functions and deoptimize them.
230 Object* element = context->OptimizedFunctionsListHead();
231 while (!element->IsUndefined()) {
232 JSFunction* element_function = JSFunction::cast(element);
233 // Get the next link before deoptimizing as deoptimizing will clear the
234 // next link.
235 element = element_function->next_function_link();
236 visitor->VisitFunction(element_function);
237 }
238 visitor->LeaveContext(context);
239}
240
241
242void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
243 JSObject* object, OptimizedFunctionVisitor* visitor) {
244 AssertNoAllocation no_allocation;
245
246 if (object->IsJSGlobalProxy()) {
247 Object* proto = object->GetPrototype();
248 ASSERT(proto->IsJSGlobalObject());
249 VisitAllOptimizedFunctionsForContext(
250 GlobalObject::cast(proto)->global_context(), visitor);
251 } else if (object->IsGlobalObject()) {
252 VisitAllOptimizedFunctionsForContext(
253 GlobalObject::cast(object)->global_context(), visitor);
254 }
255}
256
257
258void Deoptimizer::VisitAllOptimizedFunctions(
259 OptimizedFunctionVisitor* visitor) {
260 AssertNoAllocation no_allocation;
261
262 // Run through the list of all global contexts and deoptimize.
Ben Murdoch85b71792012-04-11 18:30:58 +0100263 Object* global = Isolate::Current()->heap()->global_contexts_list();
264 while (!global->IsUndefined()) {
265 VisitAllOptimizedFunctionsForGlobalObject(Context::cast(global)->global(),
266 visitor);
267 global = Context::cast(global)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100268 }
269}
270
271
272void Deoptimizer::HandleWeakDeoptimizedCode(
273 v8::Persistent<v8::Value> obj, void* data) {
274 DeoptimizingCodeListNode* node =
275 reinterpret_cast<DeoptimizingCodeListNode*>(data);
276 RemoveDeoptimizingCode(*node->code());
277#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100278 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100279 while (node != NULL) {
280 ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
281 node = node->next();
282 }
283#endif
284}
285
286
Ben Murdoch8b112d22011-06-08 16:22:53 +0100287void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100288 deoptimizer->DoComputeOutputFrames();
289}
290
291
Steve Block44f0eee2011-05-26 01:26:41 +0100292Deoptimizer::Deoptimizer(Isolate* isolate,
293 JSFunction* function,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100294 BailoutType type,
295 unsigned bailout_id,
296 Address from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000297 int fp_to_sp_delta,
298 Code* optimized_code)
Steve Block44f0eee2011-05-26 01:26:41 +0100299 : isolate_(isolate),
300 function_(function),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100301 bailout_id_(bailout_id),
302 bailout_type_(type),
303 from_(from),
304 fp_to_sp_delta_(fp_to_sp_delta),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000305 input_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100306 output_count_(0),
307 output_(NULL),
Ben Murdoch8b112d22011-06-08 16:22:53 +0100308 deferred_heap_numbers_(0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309 if (FLAG_trace_deopt && type != OSR) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000310 if (type == DEBUGGER) {
311 PrintF("**** DEOPT FOR DEBUGGER: ");
312 } else {
313 PrintF("**** DEOPT: ");
314 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100315 function->PrintName();
316 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
317 bailout_id,
318 reinterpret_cast<intptr_t>(from),
319 fp_to_sp_delta - (2 * kPointerSize));
320 } else if (FLAG_trace_osr && type == OSR) {
321 PrintF("**** OSR: ");
322 function->PrintName();
323 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
324 bailout_id,
325 reinterpret_cast<intptr_t>(from),
326 fp_to_sp_delta - (2 * kPointerSize));
327 }
328 // Find the optimized code.
329 if (type == EAGER) {
330 ASSERT(from == NULL);
331 optimized_code_ = function_->code();
332 } else if (type == LAZY) {
333 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
334 ASSERT(optimized_code_ != NULL);
335 } else if (type == OSR) {
336 // The function has already been optimized and we're transitioning
337 // from the unoptimized shared version to the optimized one in the
338 // function. The return address (from) points to unoptimized code.
339 optimized_code_ = function_->code();
340 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
341 ASSERT(!optimized_code_->contains(from));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000342 } else if (type == DEBUGGER) {
343 optimized_code_ = optimized_code;
344 ASSERT(optimized_code_->contains(from));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100345 }
Steve Block44f0eee2011-05-26 01:26:41 +0100346 ASSERT(HEAP->allow_allocation(false));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100347 unsigned size = ComputeInputFrameSize();
348 input_ = new(size) FrameDescription(size, function);
Ben Murdoch85b71792012-04-11 18:30:58 +0100349#ifdef DEBUG
350 input_->SetKind(Code::OPTIMIZED_FUNCTION);
351#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100352}
353
354
355Deoptimizer::~Deoptimizer() {
356 ASSERT(input_ == NULL && output_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100357}
358
359
360void Deoptimizer::DeleteFrameDescriptions() {
361 delete input_;
362 for (int i = 0; i < output_count_; ++i) {
363 if (output_[i] != input_) delete output_[i];
364 }
365 delete[] output_;
366 input_ = NULL;
367 output_ = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100368 ASSERT(!HEAP->allow_allocation(true));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100369}
370
371
372Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
373 ASSERT(id >= 0);
374 if (id >= kNumberOfEntries) return NULL;
Ben Murdoch85b71792012-04-11 18:30:58 +0100375 LargeObjectChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100376 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100377 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100378 if (data->eager_deoptimization_entry_code_ == NULL) {
379 data->eager_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100380 }
Steve Block44f0eee2011-05-26 01:26:41 +0100381 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100382 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100383 if (data->lazy_deoptimization_entry_code_ == NULL) {
384 data->lazy_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100385 }
Steve Block44f0eee2011-05-26 01:26:41 +0100386 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100387 }
388 return
Ben Murdoch85b71792012-04-11 18:30:58 +0100389 static_cast<Address>(base->GetStartAddress()) + (id * table_entry_size_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100390}
391
392
393int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100394 LargeObjectChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100395 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100396 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100397 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100398 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100399 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100400 }
401 if (base == NULL ||
Ben Murdoch85b71792012-04-11 18:30:58 +0100402 addr < base->GetStartAddress() ||
403 addr >= base->GetStartAddress() +
Ben Murdochb0fe1622011-05-05 13:52:32 +0100404 (kNumberOfEntries * table_entry_size_)) {
405 return kNotDeoptimizationEntry;
406 }
407 ASSERT_EQ(0,
Ben Murdoch85b71792012-04-11 18:30:58 +0100408 static_cast<int>(addr - base->GetStartAddress()) % table_entry_size_);
409 return static_cast<int>(addr - base->GetStartAddress()) / table_entry_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100410}
411
412
Steve Block9fac8402011-05-12 15:51:54 +0100413int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
414 unsigned id,
415 SharedFunctionInfo* shared) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100416 // TODO(kasperl): For now, we do a simple linear search for the PC
417 // offset associated with the given node id. This should probably be
418 // changed to a binary search.
419 int length = data->DeoptPoints();
420 Smi* smi_id = Smi::FromInt(id);
421 for (int i = 0; i < length; i++) {
422 if (data->AstId(i) == smi_id) {
423 return data->PcAndState(i)->value();
424 }
425 }
426 PrintF("[couldn't find pc offset for node=%u]\n", id);
427 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
428 // Print the source code if available.
429 HeapStringAllocator string_allocator;
430 StringStream stream(&string_allocator);
431 shared->SourceCodePrint(&stream, -1);
432 PrintF("[source:\n%s\n]", *stream.ToCString());
433
434 UNREACHABLE();
435 return -1;
436}
437
438
Steve Block44f0eee2011-05-26 01:26:41 +0100439int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100440 int length = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100441 DeoptimizingCodeListNode* node =
442 isolate->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443 while (node != NULL) {
444 length++;
445 node = node->next();
446 }
447 return length;
448}
449
450
451void Deoptimizer::DoComputeOutputFrames() {
452 if (bailout_type_ == OSR) {
453 DoComputeOsrOutputFrame();
454 return;
455 }
456
457 // Print some helpful diagnostic information.
458 int64_t start = OS::Ticks();
459 if (FLAG_trace_deopt) {
460 PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
461 (bailout_type_ == LAZY ? " (lazy)" : ""),
462 reinterpret_cast<intptr_t>(function_));
463 function_->PrintName();
464 PrintF(" @%d]\n", bailout_id_);
465 }
466
467 // Determine basic deoptimization information. The optimized frame is
468 // described by the input data.
469 DeoptimizationInputData* input_data =
470 DeoptimizationInputData::cast(optimized_code_->deoptimization_data());
471 unsigned node_id = input_data->AstId(bailout_id_)->value();
472 ByteArray* translations = input_data->TranslationByteArray();
473 unsigned translation_index =
474 input_data->TranslationIndex(bailout_id_)->value();
475
476 // Do the input frame to output frame(s) translation.
477 TranslationIterator iterator(translations, translation_index);
478 Translation::Opcode opcode =
479 static_cast<Translation::Opcode>(iterator.Next());
480 ASSERT(Translation::BEGIN == opcode);
481 USE(opcode);
482 // Read the number of output frames and allocate an array for their
483 // descriptions.
484 int count = iterator.Next();
485 ASSERT(output_ == NULL);
486 output_ = new FrameDescription*[count];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100487 for (int i = 0; i < count; ++i) {
488 output_[i] = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100489 }
490 output_count_ = count;
491
492 // Translate each output frame.
493 for (int i = 0; i < count; ++i) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100494 DoComputeFrame(&iterator, i);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100495 }
496
497 // Print some helpful diagnostic information.
498 if (FLAG_trace_deopt) {
499 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
500 int index = output_count_ - 1; // Index of the topmost frame.
501 JSFunction* function = output_[index]->GetFunction();
502 PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
503 reinterpret_cast<intptr_t>(function));
504 function->PrintName();
505 PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
506 node_id,
507 output_[index]->GetPc(),
508 FullCodeGenerator::State2String(
509 static_cast<FullCodeGenerator::State>(
510 output_[index]->GetState()->value())),
511 ms);
512 }
513}
514
515
Ben Murdoch8b112d22011-06-08 16:22:53 +0100516void Deoptimizer::MaterializeHeapNumbers() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000517 ASSERT_NE(DEBUGGER, bailout_type_);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100518 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
519 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
520 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
521 if (FLAG_trace_deopt) {
522 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
523 reinterpret_cast<void*>(*num),
524 d.value(),
525 d.slot_address());
526 }
527
528 Memory::Object_at(d.slot_address()) = *num;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100529 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100530}
531
532
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000533#ifdef ENABLE_DEBUGGER_SUPPORT
534void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdoch85b71792012-04-11 18:30:58 +0100535 Address top, uint32_t size, DeoptimizedFrameInfo* info) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000536 ASSERT_EQ(DEBUGGER, bailout_type_);
537 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
538 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
539
540 // Check of the heap number to materialize actually belong to the frame
541 // being extracted.
542 Address slot = d.slot_address();
Ben Murdoch85b71792012-04-11 18:30:58 +0100543 if (top <= slot && slot < top + size) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000544 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
Ben Murdoch85b71792012-04-11 18:30:58 +0100545 // Calculate the index with the botton of the expression stack
546 // at index 0, and the fixed part (including incoming arguments)
547 // at negative indexes.
548 int index = static_cast<int>(
549 info->expression_count_ - (slot - top) / kPointerSize - 1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000550 if (FLAG_trace_deopt) {
551 PrintF("Materializing a new heap number %p [%e] in slot %p"
Ben Murdoch85b71792012-04-11 18:30:58 +0100552 "for stack index %d\n",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000553 reinterpret_cast<void*>(*num),
554 d.value(),
555 d.slot_address(),
556 index);
557 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100558 if (index >=0) {
559 info->SetExpression(index, *num);
560 } else {
561 // Calculate parameter index subtracting one for the receiver.
562 int parameter_index =
563 index +
564 static_cast<int>(size) / kPointerSize -
565 info->expression_count_ - 1;
566 info->SetParameter(parameter_index, *num);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000567 }
568 }
569 }
570}
571#endif
572
573
Ben Murdochb0fe1622011-05-05 13:52:32 +0100574void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
575 int frame_index,
576 unsigned output_offset) {
577 disasm::NameConverter converter;
578 // A GC-safe temporary placeholder that we can put in the output frame.
579 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
580
581 // Ignore commands marked as duplicate and act on the first non-duplicate.
582 Translation::Opcode opcode =
583 static_cast<Translation::Opcode>(iterator->Next());
584 while (opcode == Translation::DUPLICATE) {
585 opcode = static_cast<Translation::Opcode>(iterator->Next());
586 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
587 opcode = static_cast<Translation::Opcode>(iterator->Next());
588 }
589
590 switch (opcode) {
591 case Translation::BEGIN:
Ben Murdoch85b71792012-04-11 18:30:58 +0100592 case Translation::FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100593 case Translation::DUPLICATE:
594 UNREACHABLE();
595 return;
596
597 case Translation::REGISTER: {
598 int input_reg = iterator->Next();
599 intptr_t input_value = input_->GetRegister(input_reg);
600 if (FLAG_trace_deopt) {
601 PrintF(
Ben Murdoch85b71792012-04-11 18:30:58 +0100602 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100603 output_[frame_index]->GetTop() + output_offset,
604 output_offset,
605 input_value,
606 converter.NameOfCPURegister(input_reg));
607 }
608 output_[frame_index]->SetFrameSlot(output_offset, input_value);
609 return;
610 }
611
612 case Translation::INT32_REGISTER: {
613 int input_reg = iterator->Next();
614 intptr_t value = input_->GetRegister(input_reg);
615 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100616 if (FLAG_trace_deopt) {
617 PrintF(
618 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
619 output_[frame_index]->GetTop() + output_offset,
620 output_offset,
621 value,
622 converter.NameOfCPURegister(input_reg),
623 is_smi ? "smi" : "heap number");
624 }
625 if (is_smi) {
626 intptr_t tagged_value =
627 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
628 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
629 } else {
630 // We save the untagged value on the side and store a GC-safe
631 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100632 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
633 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100634 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
635 }
636 return;
637 }
638
639 case Translation::DOUBLE_REGISTER: {
640 int input_reg = iterator->Next();
641 double value = input_->GetDoubleRegister(input_reg);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100642 if (FLAG_trace_deopt) {
643 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
644 output_[frame_index]->GetTop() + output_offset,
645 output_offset,
646 value,
647 DoubleRegister::AllocationIndexToString(input_reg));
648 }
649 // We save the untagged value on the side and store a GC-safe
650 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100651 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100652 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
653 return;
654 }
655
656 case Translation::STACK_SLOT: {
657 int input_slot_index = iterator->Next();
658 unsigned input_offset =
Ben Murdoch85b71792012-04-11 18:30:58 +0100659 input_->GetOffsetFromSlotIndex(this, input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100660 intptr_t input_value = input_->GetFrameSlot(input_offset);
661 if (FLAG_trace_deopt) {
662 PrintF(" 0x%08" V8PRIxPTR ": ",
663 output_[frame_index]->GetTop() + output_offset);
Ben Murdoch85b71792012-04-11 18:30:58 +0100664 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100665 output_offset,
666 input_value,
667 input_offset);
668 }
669 output_[frame_index]->SetFrameSlot(output_offset, input_value);
670 return;
671 }
672
673 case Translation::INT32_STACK_SLOT: {
674 int input_slot_index = iterator->Next();
675 unsigned input_offset =
Ben Murdoch85b71792012-04-11 18:30:58 +0100676 input_->GetOffsetFromSlotIndex(this, input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100677 intptr_t value = input_->GetFrameSlot(input_offset);
678 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100679 if (FLAG_trace_deopt) {
680 PrintF(" 0x%08" V8PRIxPTR ": ",
681 output_[frame_index]->GetTop() + output_offset);
682 PrintF("[top + %d] <- %" V8PRIdPTR " ; [esp + %d] (%s)\n",
683 output_offset,
684 value,
685 input_offset,
686 is_smi ? "smi" : "heap number");
687 }
688 if (is_smi) {
689 intptr_t tagged_value =
690 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
691 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
692 } else {
693 // We save the untagged value on the side and store a GC-safe
694 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100695 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
696 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100697 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
698 }
699 return;
700 }
701
702 case Translation::DOUBLE_STACK_SLOT: {
703 int input_slot_index = iterator->Next();
704 unsigned input_offset =
Ben Murdoch85b71792012-04-11 18:30:58 +0100705 input_->GetOffsetFromSlotIndex(this, input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100706 double value = input_->GetDoubleFrameSlot(input_offset);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100707 if (FLAG_trace_deopt) {
708 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
709 output_[frame_index]->GetTop() + output_offset,
710 output_offset,
711 value,
712 input_offset);
713 }
714 // We save the untagged value on the side and store a GC-safe
715 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100716 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100717 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
718 return;
719 }
720
721 case Translation::LITERAL: {
722 Object* literal = ComputeLiteral(iterator->Next());
723 if (FLAG_trace_deopt) {
724 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
725 output_[frame_index]->GetTop() + output_offset,
726 output_offset);
727 literal->ShortPrint();
728 PrintF(" ; literal\n");
729 }
730 intptr_t value = reinterpret_cast<intptr_t>(literal);
731 output_[frame_index]->SetFrameSlot(output_offset, value);
732 return;
733 }
734
735 case Translation::ARGUMENTS_OBJECT: {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100736 // Use the arguments marker value as a sentinel and fill in the arguments
737 // object after the deoptimized frame is built.
Ben Murdoch85b71792012-04-11 18:30:58 +0100738 ASSERT(frame_index == 0); // Only supported for first frame.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100739 if (FLAG_trace_deopt) {
740 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
741 output_[frame_index]->GetTop() + output_offset,
742 output_offset);
Steve Block44f0eee2011-05-26 01:26:41 +0100743 isolate_->heap()->arguments_marker()->ShortPrint();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100744 PrintF(" ; arguments object\n");
745 }
Steve Block44f0eee2011-05-26 01:26:41 +0100746 intptr_t value = reinterpret_cast<intptr_t>(
747 isolate_->heap()->arguments_marker());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100748 output_[frame_index]->SetFrameSlot(output_offset, value);
749 return;
750 }
751 }
752}
753
754
755bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
756 int* input_offset) {
757 disasm::NameConverter converter;
758 FrameDescription* output = output_[0];
759
760 // The input values are all part of the unoptimized frame so they
761 // are all tagged pointers.
762 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
763 Object* input_object = reinterpret_cast<Object*>(input_value);
764
765 Translation::Opcode opcode =
766 static_cast<Translation::Opcode>(iterator->Next());
767 bool duplicate = (opcode == Translation::DUPLICATE);
768 if (duplicate) {
769 opcode = static_cast<Translation::Opcode>(iterator->Next());
770 }
771
772 switch (opcode) {
773 case Translation::BEGIN:
Ben Murdoch85b71792012-04-11 18:30:58 +0100774 case Translation::FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100775 case Translation::DUPLICATE:
776 UNREACHABLE(); // Malformed input.
777 return false;
778
779 case Translation::REGISTER: {
780 int output_reg = iterator->Next();
781 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100782 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100783 converter.NameOfCPURegister(output_reg),
784 input_value,
785 *input_offset);
786 }
787 output->SetRegister(output_reg, input_value);
788 break;
789 }
790
791 case Translation::INT32_REGISTER: {
792 // Abort OSR if we don't have a number.
793 if (!input_object->IsNumber()) return false;
794
795 int output_reg = iterator->Next();
796 int int32_value = input_object->IsSmi()
797 ? Smi::cast(input_object)->value()
798 : FastD2I(input_object->Number());
799 // Abort the translation if the conversion lost information.
800 if (!input_object->IsSmi() &&
801 FastI2D(int32_value) != input_object->Number()) {
802 if (FLAG_trace_osr) {
803 PrintF("**** %g could not be converted to int32 ****\n",
804 input_object->Number());
805 }
806 return false;
807 }
808 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100809 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100810 converter.NameOfCPURegister(output_reg),
811 int32_value,
812 *input_offset);
813 }
814 output->SetRegister(output_reg, int32_value);
815 break;
816 }
817
818 case Translation::DOUBLE_REGISTER: {
819 // Abort OSR if we don't have a number.
820 if (!input_object->IsNumber()) return false;
821
822 int output_reg = iterator->Next();
823 double double_value = input_object->Number();
824 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100825 PrintF(" %s <- %g (double) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100826 DoubleRegister::AllocationIndexToString(output_reg),
827 double_value,
828 *input_offset);
829 }
830 output->SetDoubleRegister(output_reg, double_value);
831 break;
832 }
833
834 case Translation::STACK_SLOT: {
835 int output_index = iterator->Next();
836 unsigned output_offset =
Ben Murdoch85b71792012-04-11 18:30:58 +0100837 output->GetOffsetFromSlotIndex(this, output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100838 if (FLAG_trace_osr) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100839 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100840 output_offset,
841 input_value,
842 *input_offset);
843 }
844 output->SetFrameSlot(output_offset, input_value);
845 break;
846 }
847
848 case Translation::INT32_STACK_SLOT: {
849 // Abort OSR if we don't have a number.
850 if (!input_object->IsNumber()) return false;
851
852 int output_index = iterator->Next();
853 unsigned output_offset =
Ben Murdoch85b71792012-04-11 18:30:58 +0100854 output->GetOffsetFromSlotIndex(this, output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100855 int int32_value = input_object->IsSmi()
856 ? Smi::cast(input_object)->value()
857 : DoubleToInt32(input_object->Number());
858 // Abort the translation if the conversion lost information.
859 if (!input_object->IsSmi() &&
860 FastI2D(int32_value) != input_object->Number()) {
861 if (FLAG_trace_osr) {
862 PrintF("**** %g could not be converted to int32 ****\n",
863 input_object->Number());
864 }
865 return false;
866 }
867 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100868 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100869 output_offset,
870 int32_value,
871 *input_offset);
872 }
873 output->SetFrameSlot(output_offset, int32_value);
874 break;
875 }
876
877 case Translation::DOUBLE_STACK_SLOT: {
878 static const int kLowerOffset = 0 * kPointerSize;
879 static const int kUpperOffset = 1 * kPointerSize;
880
881 // Abort OSR if we don't have a number.
882 if (!input_object->IsNumber()) return false;
883
884 int output_index = iterator->Next();
885 unsigned output_offset =
Ben Murdoch85b71792012-04-11 18:30:58 +0100886 output->GetOffsetFromSlotIndex(this, output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100887 double double_value = input_object->Number();
888 uint64_t int_value = BitCast<uint64_t, double>(double_value);
889 int32_t lower = static_cast<int32_t>(int_value);
890 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
891 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100892 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100893 output_offset + kUpperOffset,
894 upper,
895 double_value,
896 *input_offset);
Steve Block1e0659c2011-05-24 12:43:12 +0100897 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100898 output_offset + kLowerOffset,
899 lower,
900 double_value,
901 *input_offset);
902 }
903 output->SetFrameSlot(output_offset + kLowerOffset, lower);
904 output->SetFrameSlot(output_offset + kUpperOffset, upper);
905 break;
906 }
907
908 case Translation::LITERAL: {
909 // Just ignore non-materialized literals.
910 iterator->Next();
911 break;
912 }
913
914 case Translation::ARGUMENTS_OBJECT: {
915 // Optimized code assumes that the argument object has not been
916 // materialized and so bypasses it when doing arguments access.
917 // We should have bailed out before starting the frame
918 // translation.
919 UNREACHABLE();
920 return false;
921 }
922 }
923
924 if (!duplicate) *input_offset -= kPointerSize;
925 return true;
926}
927
928
Steve Block1e0659c2011-05-24 12:43:12 +0100929void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
930 Code* check_code,
931 Code* replacement_code) {
932 // Iterate over the stack check table and patch every stack check
933 // call to an unconditional call to the replacement code.
934 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
935 Address stack_check_cursor = unoptimized_code->instruction_start() +
936 unoptimized_code->stack_check_table_offset();
937 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
938 stack_check_cursor += kIntSize;
939 for (uint32_t i = 0; i < table_length; ++i) {
940 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
941 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch85b71792012-04-11 18:30:58 +0100942 PatchStackCheckCodeAt(pc_after, check_code, replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +0100943 stack_check_cursor += 2 * kIntSize;
944 }
945}
946
947
948void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
949 Code* check_code,
950 Code* replacement_code) {
951 // Iterate over the stack check table and revert the patched
952 // stack check calls.
953 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
954 Address stack_check_cursor = unoptimized_code->instruction_start() +
955 unoptimized_code->stack_check_table_offset();
956 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
957 stack_check_cursor += kIntSize;
958 for (uint32_t i = 0; i < table_length; ++i) {
959 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
960 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch85b71792012-04-11 18:30:58 +0100961 RevertStackCheckCodeAt(pc_after, check_code, replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +0100962 stack_check_cursor += 2 * kIntSize;
963 }
964}
965
966
Ben Murdochb0fe1622011-05-05 13:52:32 +0100967unsigned Deoptimizer::ComputeInputFrameSize() const {
968 unsigned fixed_size = ComputeFixedSize(function_);
969 // The fp-to-sp delta already takes the context and the function
970 // into account so we have to avoid double counting them (-2).
971 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
972#ifdef DEBUG
973 if (bailout_type_ == OSR) {
974 // TODO(kasperl): It would be nice if we could verify that the
975 // size matches with the stack height we can compute based on the
976 // environment at the OSR entry. The code for that his built into
977 // the DoComputeOsrOutputFrame function for now.
978 } else {
979 unsigned stack_slots = optimized_code_->stack_slots();
980 unsigned outgoing_size = ComputeOutgoingArgumentSize();
981 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
982 }
983#endif
984 return result;
985}
986
987
988unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
989 // The fixed part of the frame consists of the return address, frame
990 // pointer, function, context, and all the incoming arguments.
Ben Murdoch85b71792012-04-11 18:30:58 +0100991 static const unsigned kFixedSlotSize = 4 * kPointerSize;
992 return ComputeIncomingArgumentSize(function) + kFixedSlotSize;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100993}
994
995
996unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
997 // The incoming arguments is the values for formal parameters and
998 // the receiver. Every slot contains a pointer.
999 unsigned arguments = function->shared()->formal_parameter_count() + 1;
1000 return arguments * kPointerSize;
1001}
1002
1003
1004unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
1005 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1006 optimized_code_->deoptimization_data());
1007 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
1008 return height * kPointerSize;
1009}
1010
1011
1012Object* Deoptimizer::ComputeLiteral(int index) const {
1013 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1014 optimized_code_->deoptimization_data());
1015 FixedArray* literals = data->LiteralArray();
1016 return literals->get(index);
1017}
1018
1019
Ben Murdoch8b112d22011-06-08 16:22:53 +01001020void Deoptimizer::AddDoubleValue(intptr_t slot_address,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001021 double value) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001022 HeapNumberMaterializationDescriptor value_desc(
1023 reinterpret_cast<Address>(slot_address), value);
1024 deferred_heap_numbers_.Add(value_desc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001025}
1026
1027
Ben Murdoch85b71792012-04-11 18:30:58 +01001028LargeObjectChunk* Deoptimizer::CreateCode(BailoutType type) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001029 // We cannot run this if the serializer is enabled because this will
1030 // cause us to emit relocation information for the external
1031 // references. This is fine because the deoptimizer's code section
1032 // isn't meant to be serialized at all.
1033 ASSERT(!Serializer::enabled());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001034
Ben Murdoch8b112d22011-06-08 16:22:53 +01001035 MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
Steve Block44f0eee2011-05-26 01:26:41 +01001036 masm.set_emit_debug_code(false);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001037 GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
1038 CodeDesc desc;
1039 masm.GetCode(&desc);
1040 ASSERT(desc.reloc_size == 0);
1041
Ben Murdoch85b71792012-04-11 18:30:58 +01001042 LargeObjectChunk* chunk = LargeObjectChunk::New(desc.instr_size, EXECUTABLE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001043 if (chunk == NULL) {
1044 V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
1045 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001046 memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size);
1047 CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001048 return chunk;
1049}
1050
1051
1052Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001053 DeoptimizingCodeListNode* node =
1054 Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001055 while (node != NULL) {
1056 if (node->code()->contains(addr)) return *node->code();
1057 node = node->next();
1058 }
1059 return NULL;
1060}
1061
1062
1063void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
Steve Block44f0eee2011-05-26 01:26:41 +01001064 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
1065 ASSERT(data->deoptimizing_code_list_ != NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001066 // Run through the code objects to find this one and remove it.
1067 DeoptimizingCodeListNode* prev = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01001068 DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001069 while (current != NULL) {
1070 if (*current->code() == code) {
1071 // Unlink from list. If prev is NULL we are looking at the first element.
1072 if (prev == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001073 data->deoptimizing_code_list_ = current->next();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001074 } else {
1075 prev->set_next(current->next());
1076 }
1077 delete current;
1078 return;
1079 }
1080 // Move to next in list.
1081 prev = current;
1082 current = current->next();
1083 }
1084 // Deoptimizing code is removed through weak callback. Each object is expected
1085 // to be removed once and only once.
1086 UNREACHABLE();
1087}
1088
1089
1090FrameDescription::FrameDescription(uint32_t frame_size,
1091 JSFunction* function)
1092 : frame_size_(frame_size),
1093 function_(function),
1094 top_(kZapUint32),
1095 pc_(kZapUint32),
Ben Murdoch85b71792012-04-11 18:30:58 +01001096 fp_(kZapUint32) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001097 // Zap all the registers.
1098 for (int r = 0; r < Register::kNumRegisters; r++) {
1099 SetRegister(r, kZapUint32);
1100 }
1101
1102 // Zap all the slots.
1103 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
1104 SetFrameSlot(o, kZapUint32);
1105 }
1106}
1107
1108
Ben Murdoch85b71792012-04-11 18:30:58 +01001109unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer,
1110 int slot_index) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001111 if (slot_index >= 0) {
1112 // Local or spill slots. Skip the fixed part of the frame
1113 // including all arguments.
Ben Murdoch85b71792012-04-11 18:30:58 +01001114 unsigned base =
1115 GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001116 return base - ((slot_index + 1) * kPointerSize);
1117 } else {
1118 // Incoming parameter.
Ben Murdoch85b71792012-04-11 18:30:58 +01001119 unsigned base = GetFrameSize() -
1120 deoptimizer->ComputeIncomingArgumentSize(GetFunction());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001121 return base - ((slot_index + 1) * kPointerSize);
1122 }
1123}
1124
1125
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001126int FrameDescription::ComputeParametersCount() {
Ben Murdoch85b71792012-04-11 18:30:58 +01001127 return function_->shared()->formal_parameter_count();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001128}
1129
1130
Ben Murdoch85b71792012-04-11 18:30:58 +01001131Object* FrameDescription::GetParameter(Deoptimizer* deoptimizer, int index) {
1132 ASSERT_EQ(Code::FUNCTION, kind_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001133 ASSERT(index >= 0);
1134 ASSERT(index < ComputeParametersCount());
1135 // The slot indexes for incoming arguments are negative.
Ben Murdoch85b71792012-04-11 18:30:58 +01001136 unsigned offset = GetOffsetFromSlotIndex(deoptimizer,
1137 index - ComputeParametersCount());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001138 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1139}
1140
1141
Ben Murdoch85b71792012-04-11 18:30:58 +01001142unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) {
1143 ASSERT_EQ(Code::FUNCTION, kind_);
1144 unsigned size = GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001145 return size / kPointerSize;
1146}
1147
1148
Ben Murdoch85b71792012-04-11 18:30:58 +01001149Object* FrameDescription::GetExpression(Deoptimizer* deoptimizer, int index) {
1150 ASSERT_EQ(Code::FUNCTION, kind_);
1151 unsigned offset = GetOffsetFromSlotIndex(deoptimizer, index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001152 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1153}
1154
1155
Ben Murdochb0fe1622011-05-05 13:52:32 +01001156void TranslationBuffer::Add(int32_t value) {
1157 // Encode the sign bit in the least significant bit.
1158 bool is_negative = (value < 0);
1159 uint32_t bits = ((is_negative ? -value : value) << 1) |
1160 static_cast<int32_t>(is_negative);
1161 // Encode the individual bytes using the least significant bit of
1162 // each byte to indicate whether or not more bytes follow.
1163 do {
1164 uint32_t next = bits >> 7;
1165 contents_.Add(((bits << 1) & 0xFF) | (next != 0));
1166 bits = next;
1167 } while (bits != 0);
1168}
1169
1170
1171int32_t TranslationIterator::Next() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001172 // Run through the bytes until we reach one with a least significant
1173 // bit of zero (marks the end).
1174 uint32_t bits = 0;
1175 for (int i = 0; true; i += 7) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001176 ASSERT(HasNext());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001177 uint8_t next = buffer_->get(index_++);
1178 bits |= (next >> 1) << i;
1179 if ((next & 1) == 0) break;
1180 }
1181 // The bits encode the sign in the least significant bit.
1182 bool is_negative = (bits & 1) == 1;
1183 int32_t result = bits >> 1;
1184 return is_negative ? -result : result;
1185}
1186
1187
1188Handle<ByteArray> TranslationBuffer::CreateByteArray() {
1189 int length = contents_.length();
Steve Block44f0eee2011-05-26 01:26:41 +01001190 Handle<ByteArray> result =
1191 Isolate::Current()->factory()->NewByteArray(length, TENURED);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001192 memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
1193 return result;
1194}
1195
1196
Ben Murdoch85b71792012-04-11 18:30:58 +01001197void Translation::BeginFrame(int node_id, int literal_id, unsigned height) {
1198 buffer_->Add(FRAME);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001199 buffer_->Add(node_id);
1200 buffer_->Add(literal_id);
1201 buffer_->Add(height);
1202}
1203
1204
1205void Translation::StoreRegister(Register reg) {
1206 buffer_->Add(REGISTER);
1207 buffer_->Add(reg.code());
1208}
1209
1210
1211void Translation::StoreInt32Register(Register reg) {
1212 buffer_->Add(INT32_REGISTER);
1213 buffer_->Add(reg.code());
1214}
1215
1216
1217void Translation::StoreDoubleRegister(DoubleRegister reg) {
1218 buffer_->Add(DOUBLE_REGISTER);
1219 buffer_->Add(DoubleRegister::ToAllocationIndex(reg));
1220}
1221
1222
1223void Translation::StoreStackSlot(int index) {
1224 buffer_->Add(STACK_SLOT);
1225 buffer_->Add(index);
1226}
1227
1228
1229void Translation::StoreInt32StackSlot(int index) {
1230 buffer_->Add(INT32_STACK_SLOT);
1231 buffer_->Add(index);
1232}
1233
1234
1235void Translation::StoreDoubleStackSlot(int index) {
1236 buffer_->Add(DOUBLE_STACK_SLOT);
1237 buffer_->Add(index);
1238}
1239
1240
1241void Translation::StoreLiteral(int literal_id) {
1242 buffer_->Add(LITERAL);
1243 buffer_->Add(literal_id);
1244}
1245
1246
1247void Translation::StoreArgumentsObject() {
1248 buffer_->Add(ARGUMENTS_OBJECT);
1249}
1250
1251
1252void Translation::MarkDuplicate() {
1253 buffer_->Add(DUPLICATE);
1254}
1255
1256
1257int Translation::NumberOfOperandsFor(Opcode opcode) {
1258 switch (opcode) {
1259 case ARGUMENTS_OBJECT:
1260 case DUPLICATE:
1261 return 0;
Ben Murdoch85b71792012-04-11 18:30:58 +01001262 case BEGIN:
Ben Murdochb0fe1622011-05-05 13:52:32 +01001263 case REGISTER:
1264 case INT32_REGISTER:
1265 case DOUBLE_REGISTER:
1266 case STACK_SLOT:
1267 case INT32_STACK_SLOT:
1268 case DOUBLE_STACK_SLOT:
1269 case LITERAL:
1270 return 1;
Ben Murdoch85b71792012-04-11 18:30:58 +01001271 case FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +01001272 return 3;
1273 }
1274 UNREACHABLE();
1275 return -1;
1276}
1277
1278
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001279#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001280
1281const char* Translation::StringFor(Opcode opcode) {
1282 switch (opcode) {
1283 case BEGIN:
1284 return "BEGIN";
Ben Murdoch85b71792012-04-11 18:30:58 +01001285 case FRAME:
1286 return "FRAME";
Ben Murdochb0fe1622011-05-05 13:52:32 +01001287 case REGISTER:
1288 return "REGISTER";
1289 case INT32_REGISTER:
1290 return "INT32_REGISTER";
1291 case DOUBLE_REGISTER:
1292 return "DOUBLE_REGISTER";
1293 case STACK_SLOT:
1294 return "STACK_SLOT";
1295 case INT32_STACK_SLOT:
1296 return "INT32_STACK_SLOT";
1297 case DOUBLE_STACK_SLOT:
1298 return "DOUBLE_STACK_SLOT";
1299 case LITERAL:
1300 return "LITERAL";
1301 case ARGUMENTS_OBJECT:
1302 return "ARGUMENTS_OBJECT";
1303 case DUPLICATE:
1304 return "DUPLICATE";
1305 }
1306 UNREACHABLE();
1307 return "";
1308}
1309
1310#endif
1311
1312
1313DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001314 GlobalHandles* global_handles = Isolate::Current()->global_handles();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001315 // Globalize the code object and make it weak.
Steve Block44f0eee2011-05-26 01:26:41 +01001316 code_ = Handle<Code>::cast(global_handles->Create(code));
1317 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
1318 this,
1319 Deoptimizer::HandleWeakDeoptimizedCode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001320}
1321
1322
1323DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
Steve Block44f0eee2011-05-26 01:26:41 +01001324 GlobalHandles* global_handles = Isolate::Current()->global_handles();
1325 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001326}
1327
1328
Ben Murdoch8b112d22011-06-08 16:22:53 +01001329// We can't intermix stack decoding and allocations because
1330// deoptimization infrastracture is not GC safe.
1331// Thus we build a temporary structure in malloced space.
1332SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
1333 DeoptimizationInputData* data,
1334 JavaScriptFrame* frame) {
1335 Translation::Opcode opcode =
1336 static_cast<Translation::Opcode>(iterator->Next());
1337
1338 switch (opcode) {
1339 case Translation::BEGIN:
Ben Murdoch85b71792012-04-11 18:30:58 +01001340 case Translation::FRAME:
Ben Murdoch8b112d22011-06-08 16:22:53 +01001341 // Peeled off before getting here.
1342 break;
1343
1344 case Translation::ARGUMENTS_OBJECT:
1345 // This can be only emitted for local slots not for argument slots.
1346 break;
1347
1348 case Translation::REGISTER:
1349 case Translation::INT32_REGISTER:
1350 case Translation::DOUBLE_REGISTER:
1351 case Translation::DUPLICATE:
1352 // We are at safepoint which corresponds to call. All registers are
1353 // saved by caller so there would be no live registers at this
1354 // point. Thus these translation commands should not be used.
1355 break;
1356
1357 case Translation::STACK_SLOT: {
1358 int slot_index = iterator->Next();
1359 Address slot_addr = SlotAddress(frame, slot_index);
1360 return SlotRef(slot_addr, SlotRef::TAGGED);
1361 }
1362
1363 case Translation::INT32_STACK_SLOT: {
1364 int slot_index = iterator->Next();
1365 Address slot_addr = SlotAddress(frame, slot_index);
1366 return SlotRef(slot_addr, SlotRef::INT32);
1367 }
1368
1369 case Translation::DOUBLE_STACK_SLOT: {
1370 int slot_index = iterator->Next();
1371 Address slot_addr = SlotAddress(frame, slot_index);
1372 return SlotRef(slot_addr, SlotRef::DOUBLE);
1373 }
1374
1375 case Translation::LITERAL: {
1376 int literal_index = iterator->Next();
1377 return SlotRef(data->LiteralArray()->get(literal_index));
1378 }
1379 }
1380
1381 UNREACHABLE();
1382 return SlotRef();
1383}
1384
1385
Ben Murdoch85b71792012-04-11 18:30:58 +01001386void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame,
1387 int inlined_frame_index,
1388 Vector<SlotRef>* args_slots) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001389 AssertNoAllocation no_gc;
1390 int deopt_index = AstNode::kNoNumber;
1391 DeoptimizationInputData* data =
1392 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
1393 TranslationIterator it(data->TranslationByteArray(),
1394 data->TranslationIndex(deopt_index)->value());
1395 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1396 ASSERT(opcode == Translation::BEGIN);
Ben Murdoch85b71792012-04-11 18:30:58 +01001397 int frame_count = it.Next();
1398 USE(frame_count);
1399 ASSERT(frame_count > inlined_frame_index);
1400 int frames_to_skip = inlined_frame_index;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001401 while (true) {
1402 opcode = static_cast<Translation::Opcode>(it.Next());
Ben Murdochc7cc0282012-03-05 14:35:55 +00001403 // Skip over operands to advance to the next opcode.
1404 it.Skip(Translation::NumberOfOperandsFor(opcode));
Ben Murdoch85b71792012-04-11 18:30:58 +01001405 if (opcode == Translation::FRAME) {
1406 if (frames_to_skip == 0) {
1407 // We reached the frame corresponding to the inlined function
1408 // in question. Process the translation commands for the
1409 // arguments.
1410 //
1411 // Skip the translation command for the receiver.
1412 it.Skip(Translation::NumberOfOperandsFor(
1413 static_cast<Translation::Opcode>(it.Next())));
1414 // Compute slots for arguments.
1415 for (int i = 0; i < args_slots->length(); ++i) {
1416 (*args_slots)[i] = ComputeSlotForNextArgument(&it, data, frame);
1417 }
1418 return;
1419 }
1420 frames_to_skip--;
1421 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001422 }
1423
1424 UNREACHABLE();
1425}
1426
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001427#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch8b112d22011-06-08 16:22:53 +01001428
Ben Murdoch85b71792012-04-11 18:30:58 +01001429DeoptimizedFrameInfo::DeoptimizedFrameInfo(
1430 Deoptimizer* deoptimizer, int frame_index) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001431 FrameDescription* output_frame = deoptimizer->output_[frame_index];
Ben Murdoch85b71792012-04-11 18:30:58 +01001432 SetFunction(output_frame->GetFunction());
1433 expression_count_ = output_frame->GetExpressionCount(deoptimizer);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001434 parameters_count_ = output_frame->ComputeParametersCount();
1435 parameters_ = new Object*[parameters_count_];
1436 for (int i = 0; i < parameters_count_; i++) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001437 SetParameter(i, output_frame->GetParameter(deoptimizer, i));
1438 }
1439 expression_stack_ = new Object*[expression_count_];
1440 for (int i = 0; i < expression_count_; i++) {
1441 SetExpression(i, output_frame->GetExpression(deoptimizer, i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001442 }
1443}
1444
1445
1446DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
1447 delete[] expression_stack_;
1448 delete[] parameters_;
1449}
1450
1451void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
1452 v->VisitPointer(BitCast<Object**>(&function_));
1453 v->VisitPointers(parameters_, parameters_ + parameters_count_);
1454 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
1455}
1456
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001457#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001458
Ben Murdochb0fe1622011-05-05 13:52:32 +01001459} } // namespace v8::internal