blob: 68f82ce5021ad9eb1a7d809becc37b0784a03696 [file] [log] [blame]
Ben Murdochc7cc0282012-03-05 14:35:55 +00001// Copyright 2012 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 Murdochc7cc0282012-03-05 14:35:55 +0000107
108int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) {
109 if (jsframe_index == 0) return 0;
110
111 int frame_index = 0;
112 while (jsframe_index >= 0) {
113 FrameDescription* frame = output_[frame_index];
114 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) {
115 jsframe_index--;
116 }
117 frame_index++;
118 }
119
120 return frame_index - 1;
121}
122
123
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000124#ifdef ENABLE_DEBUGGER_SUPPORT
125DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
126 JavaScriptFrame* frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +0000127 int jsframe_index,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000128 Isolate* isolate) {
129 ASSERT(isolate == Isolate::Current());
130 ASSERT(frame->is_optimized());
131 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
132
133 // Get the function and code from the frame.
134 JSFunction* function = JSFunction::cast(frame->function());
135 Code* code = frame->LookupCode();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000136
137 // Locate the deoptimization point in the code. As we are at a call the
138 // return address must be at a place in the code with deoptimization support.
Ben Murdoch2b4ba112012-01-20 14:57:15 +0000139 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
140 int deoptimization_index = safepoint_entry.deoptimization_index();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000141 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
142
143 // Always use the actual stack slots when calculating the fp to sp
144 // delta adding two for the function and context.
145 unsigned stack_slots = code->stack_slots();
146 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
147
148 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
149 function,
150 Deoptimizer::DEBUGGER,
151 deoptimization_index,
152 frame->pc(),
153 fp_to_sp_delta,
154 code);
155 Address tos = frame->fp() - fp_to_sp_delta;
156 deoptimizer->FillInputFrame(tos, frame);
157
158 // Calculate the output frames.
159 Deoptimizer::ComputeOutputFrames(deoptimizer);
160
161 // Create the GC safe output frame information and register it for GC
162 // handling.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000163 ASSERT_LT(jsframe_index, deoptimizer->jsframe_count());
164
165 // Convert JS frame index into frame index.
166 int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index);
167
168 bool has_arguments_adaptor =
169 frame_index > 0 &&
170 deoptimizer->output_[frame_index - 1]->GetFrameType() ==
171 StackFrame::ARGUMENTS_ADAPTOR;
172
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000173 DeoptimizedFrameInfo* info =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000174 new DeoptimizedFrameInfo(deoptimizer, frame_index, has_arguments_adaptor);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000175 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
176
177 // Get the "simulated" top and size for the requested frame.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000178 FrameDescription* parameters_frame =
179 deoptimizer->output_[
180 has_arguments_adaptor ? (frame_index - 1) : frame_index];
181
182 uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize;
183 Address parameters_top = reinterpret_cast<Address>(
184 parameters_frame->GetTop() + (parameters_frame->GetFrameSize() -
185 parameters_size));
186
187 uint32_t expressions_size = info->expression_count() * kPointerSize;
188 Address expressions_top = reinterpret_cast<Address>(
189 deoptimizer->output_[frame_index]->GetTop());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000190
191 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
192 deoptimizer->DeleteFrameDescriptions();
193
194 // Allocate a heap number for the doubles belonging to this frame.
195 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdochc7cc0282012-03-05 14:35:55 +0000196 parameters_top, parameters_size, expressions_top, expressions_size, info);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000197
198 // Finished using the deoptimizer instance.
199 delete deoptimizer;
200
201 return info;
202}
203
204
205void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
206 Isolate* isolate) {
207 ASSERT(isolate == Isolate::Current());
208 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
209 delete info;
210 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
211}
212#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213
214void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
215 int count,
216 BailoutType type) {
217 TableEntryGenerator generator(masm, type, count);
218 generator.Generate();
219}
220
221
222class DeoptimizingVisitor : public OptimizedFunctionVisitor {
223 public:
224 virtual void EnterContext(Context* context) {
225 if (FLAG_trace_deopt) {
226 PrintF("[deoptimize context: %" V8PRIxPTR "]\n",
227 reinterpret_cast<intptr_t>(context));
228 }
229 }
230
231 virtual void VisitFunction(JSFunction* function) {
232 Deoptimizer::DeoptimizeFunction(function);
233 }
234
235 virtual void LeaveContext(Context* context) {
236 context->ClearOptimizedFunctions();
237 }
238};
239
240
241void Deoptimizer::DeoptimizeAll() {
242 AssertNoAllocation no_allocation;
243
244 if (FLAG_trace_deopt) {
245 PrintF("[deoptimize all contexts]\n");
246 }
247
248 DeoptimizingVisitor visitor;
249 VisitAllOptimizedFunctions(&visitor);
250}
251
252
253void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
254 AssertNoAllocation no_allocation;
255
256 DeoptimizingVisitor visitor;
257 VisitAllOptimizedFunctionsForGlobalObject(object, &visitor);
258}
259
260
261void Deoptimizer::VisitAllOptimizedFunctionsForContext(
262 Context* context, OptimizedFunctionVisitor* visitor) {
263 AssertNoAllocation no_allocation;
264
265 ASSERT(context->IsGlobalContext());
266
267 visitor->EnterContext(context);
268 // Run through the list of optimized functions and deoptimize them.
269 Object* element = context->OptimizedFunctionsListHead();
270 while (!element->IsUndefined()) {
271 JSFunction* element_function = JSFunction::cast(element);
272 // Get the next link before deoptimizing as deoptimizing will clear the
273 // next link.
274 element = element_function->next_function_link();
275 visitor->VisitFunction(element_function);
276 }
277 visitor->LeaveContext(context);
278}
279
280
281void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
282 JSObject* object, OptimizedFunctionVisitor* visitor) {
283 AssertNoAllocation no_allocation;
284
285 if (object->IsJSGlobalProxy()) {
286 Object* proto = object->GetPrototype();
287 ASSERT(proto->IsJSGlobalObject());
288 VisitAllOptimizedFunctionsForContext(
289 GlobalObject::cast(proto)->global_context(), visitor);
290 } else if (object->IsGlobalObject()) {
291 VisitAllOptimizedFunctionsForContext(
292 GlobalObject::cast(object)->global_context(), visitor);
293 }
294}
295
296
297void Deoptimizer::VisitAllOptimizedFunctions(
298 OptimizedFunctionVisitor* visitor) {
299 AssertNoAllocation no_allocation;
300
301 // Run through the list of all global contexts and deoptimize.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000302 Object* context = Isolate::Current()->heap()->global_contexts_list();
303 while (!context->IsUndefined()) {
304 // GC can happen when the context is not fully initialized,
305 // so the global field of the context can be undefined.
306 Object* global = Context::cast(context)->get(Context::GLOBAL_INDEX);
307 if (!global->IsUndefined()) {
308 VisitAllOptimizedFunctionsForGlobalObject(JSObject::cast(global),
309 visitor);
310 }
311 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100312 }
313}
314
315
316void Deoptimizer::HandleWeakDeoptimizedCode(
317 v8::Persistent<v8::Value> obj, void* data) {
318 DeoptimizingCodeListNode* node =
319 reinterpret_cast<DeoptimizingCodeListNode*>(data);
320 RemoveDeoptimizingCode(*node->code());
321#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100322 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100323 while (node != NULL) {
324 ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
325 node = node->next();
326 }
327#endif
328}
329
330
Ben Murdoch8b112d22011-06-08 16:22:53 +0100331void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100332 deoptimizer->DoComputeOutputFrames();
333}
334
335
Steve Block44f0eee2011-05-26 01:26:41 +0100336Deoptimizer::Deoptimizer(Isolate* isolate,
337 JSFunction* function,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100338 BailoutType type,
339 unsigned bailout_id,
340 Address from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000341 int fp_to_sp_delta,
342 Code* optimized_code)
Steve Block44f0eee2011-05-26 01:26:41 +0100343 : isolate_(isolate),
344 function_(function),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100345 bailout_id_(bailout_id),
346 bailout_type_(type),
347 from_(from),
348 fp_to_sp_delta_(fp_to_sp_delta),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000349 input_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100350 output_count_(0),
Ben Murdochc7cc0282012-03-05 14:35:55 +0000351 jsframe_count_(0),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100352 output_(NULL),
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000353 frame_alignment_marker_(isolate->heap()->frame_alignment_marker()),
354 has_alignment_padding_(0),
Ben Murdoch8b112d22011-06-08 16:22:53 +0100355 deferred_heap_numbers_(0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100356 if (FLAG_trace_deopt && type != OSR) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000357 if (type == DEBUGGER) {
358 PrintF("**** DEOPT FOR DEBUGGER: ");
359 } else {
360 PrintF("**** DEOPT: ");
361 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100362 function->PrintName();
363 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
364 bailout_id,
365 reinterpret_cast<intptr_t>(from),
366 fp_to_sp_delta - (2 * kPointerSize));
367 } else if (FLAG_trace_osr && type == OSR) {
368 PrintF("**** OSR: ");
369 function->PrintName();
370 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
371 bailout_id,
372 reinterpret_cast<intptr_t>(from),
373 fp_to_sp_delta - (2 * kPointerSize));
374 }
375 // Find the optimized code.
376 if (type == EAGER) {
377 ASSERT(from == NULL);
378 optimized_code_ = function_->code();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000379 if (FLAG_trace_deopt && FLAG_code_comments) {
380 // Print instruction associated with this bailout.
381 const char* last_comment = NULL;
382 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
383 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
384 for (RelocIterator it(optimized_code_, mask); !it.done(); it.next()) {
385 RelocInfo* info = it.rinfo();
386 if (info->rmode() == RelocInfo::COMMENT) {
387 last_comment = reinterpret_cast<const char*>(info->data());
388 }
389 if (info->rmode() == RelocInfo::RUNTIME_ENTRY) {
390 unsigned id = Deoptimizer::GetDeoptimizationId(
391 info->target_address(), Deoptimizer::EAGER);
392 if (id == bailout_id && last_comment != NULL) {
393 PrintF(" %s\n", last_comment);
394 break;
395 }
396 }
397 }
398 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100399 } else if (type == LAZY) {
400 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
401 ASSERT(optimized_code_ != NULL);
402 } else if (type == OSR) {
403 // The function has already been optimized and we're transitioning
404 // from the unoptimized shared version to the optimized one in the
405 // function. The return address (from) points to unoptimized code.
406 optimized_code_ = function_->code();
407 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
408 ASSERT(!optimized_code_->contains(from));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000409 } else if (type == DEBUGGER) {
410 optimized_code_ = optimized_code;
411 ASSERT(optimized_code_->contains(from));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100412 }
Steve Block44f0eee2011-05-26 01:26:41 +0100413 ASSERT(HEAP->allow_allocation(false));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100414 unsigned size = ComputeInputFrameSize();
415 input_ = new(size) FrameDescription(size, function);
Ben Murdochc7cc0282012-03-05 14:35:55 +0000416 input_->SetFrameType(StackFrame::JAVA_SCRIPT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100417}
418
419
420Deoptimizer::~Deoptimizer() {
421 ASSERT(input_ == NULL && output_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100422}
423
424
425void Deoptimizer::DeleteFrameDescriptions() {
426 delete input_;
427 for (int i = 0; i < output_count_; ++i) {
428 if (output_[i] != input_) delete output_[i];
429 }
430 delete[] output_;
431 input_ = NULL;
432 output_ = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100433 ASSERT(!HEAP->allow_allocation(true));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100434}
435
436
437Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
438 ASSERT(id >= 0);
439 if (id >= kNumberOfEntries) return NULL;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000440 MemoryChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100441 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100442 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100443 if (data->eager_deoptimization_entry_code_ == NULL) {
444 data->eager_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100445 }
Steve Block44f0eee2011-05-26 01:26:41 +0100446 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100447 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100448 if (data->lazy_deoptimization_entry_code_ == NULL) {
449 data->lazy_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100450 }
Steve Block44f0eee2011-05-26 01:26:41 +0100451 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100452 }
453 return
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000454 static_cast<Address>(base->area_start()) + (id * table_entry_size_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100455}
456
457
458int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000459 MemoryChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100460 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100461 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100462 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100463 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100464 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100465 }
466 if (base == NULL ||
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000467 addr < base->area_start() ||
468 addr >= base->area_start() +
Ben Murdochb0fe1622011-05-05 13:52:32 +0100469 (kNumberOfEntries * table_entry_size_)) {
470 return kNotDeoptimizationEntry;
471 }
472 ASSERT_EQ(0,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000473 static_cast<int>(addr - base->area_start()) % table_entry_size_);
474 return static_cast<int>(addr - base->area_start()) / table_entry_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100475}
476
477
Steve Block9fac8402011-05-12 15:51:54 +0100478int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
479 unsigned id,
480 SharedFunctionInfo* shared) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100481 // TODO(kasperl): For now, we do a simple linear search for the PC
482 // offset associated with the given node id. This should probably be
483 // changed to a binary search.
484 int length = data->DeoptPoints();
485 Smi* smi_id = Smi::FromInt(id);
486 for (int i = 0; i < length; i++) {
487 if (data->AstId(i) == smi_id) {
488 return data->PcAndState(i)->value();
489 }
490 }
491 PrintF("[couldn't find pc offset for node=%u]\n", id);
492 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
493 // Print the source code if available.
494 HeapStringAllocator string_allocator;
495 StringStream stream(&string_allocator);
496 shared->SourceCodePrint(&stream, -1);
497 PrintF("[source:\n%s\n]", *stream.ToCString());
498
499 UNREACHABLE();
500 return -1;
501}
502
503
Steve Block44f0eee2011-05-26 01:26:41 +0100504int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100505 int length = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100506 DeoptimizingCodeListNode* node =
507 isolate->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100508 while (node != NULL) {
509 length++;
510 node = node->next();
511 }
512 return length;
513}
514
515
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000516// We rely on this function not causing a GC. It is called from generated code
517// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100518void Deoptimizer::DoComputeOutputFrames() {
519 if (bailout_type_ == OSR) {
520 DoComputeOsrOutputFrame();
521 return;
522 }
523
524 // Print some helpful diagnostic information.
525 int64_t start = OS::Ticks();
526 if (FLAG_trace_deopt) {
527 PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
528 (bailout_type_ == LAZY ? " (lazy)" : ""),
529 reinterpret_cast<intptr_t>(function_));
530 function_->PrintName();
531 PrintF(" @%d]\n", bailout_id_);
532 }
533
534 // Determine basic deoptimization information. The optimized frame is
535 // described by the input data.
536 DeoptimizationInputData* input_data =
537 DeoptimizationInputData::cast(optimized_code_->deoptimization_data());
538 unsigned node_id = input_data->AstId(bailout_id_)->value();
539 ByteArray* translations = input_data->TranslationByteArray();
540 unsigned translation_index =
541 input_data->TranslationIndex(bailout_id_)->value();
542
543 // Do the input frame to output frame(s) translation.
544 TranslationIterator iterator(translations, translation_index);
545 Translation::Opcode opcode =
546 static_cast<Translation::Opcode>(iterator.Next());
547 ASSERT(Translation::BEGIN == opcode);
548 USE(opcode);
549 // Read the number of output frames and allocate an array for their
550 // descriptions.
551 int count = iterator.Next();
Ben Murdochc7cc0282012-03-05 14:35:55 +0000552 iterator.Next(); // Drop JS frames count.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100553 ASSERT(output_ == NULL);
554 output_ = new FrameDescription*[count];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100555 for (int i = 0; i < count; ++i) {
556 output_[i] = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100557 }
558 output_count_ = count;
559
560 // Translate each output frame.
561 for (int i = 0; i < count; ++i) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000562 // Read the ast node id, function, and frame height for this output frame.
563 Translation::Opcode opcode =
564 static_cast<Translation::Opcode>(iterator.Next());
565 switch (opcode) {
566 case Translation::JS_FRAME:
567 DoComputeJSFrame(&iterator, i);
568 jsframe_count_++;
569 break;
570 case Translation::ARGUMENTS_ADAPTOR_FRAME:
571 DoComputeArgumentsAdaptorFrame(&iterator, i);
572 break;
573 default:
574 UNREACHABLE();
575 break;
576 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100577 }
578
579 // Print some helpful diagnostic information.
580 if (FLAG_trace_deopt) {
581 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
582 int index = output_count_ - 1; // Index of the topmost frame.
583 JSFunction* function = output_[index]->GetFunction();
584 PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
585 reinterpret_cast<intptr_t>(function));
586 function->PrintName();
587 PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
588 node_id,
589 output_[index]->GetPc(),
590 FullCodeGenerator::State2String(
591 static_cast<FullCodeGenerator::State>(
592 output_[index]->GetState()->value())),
593 ms);
594 }
595}
596
597
Ben Murdoch8b112d22011-06-08 16:22:53 +0100598void Deoptimizer::MaterializeHeapNumbers() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000599 ASSERT_NE(DEBUGGER, bailout_type_);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100600 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
601 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
602 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
603 if (FLAG_trace_deopt) {
604 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
605 reinterpret_cast<void*>(*num),
606 d.value(),
607 d.slot_address());
608 }
609
610 Memory::Object_at(d.slot_address()) = *num;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100611 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612}
613
614
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000615#ifdef ENABLE_DEBUGGER_SUPPORT
616void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdochc7cc0282012-03-05 14:35:55 +0000617 Address parameters_top,
618 uint32_t parameters_size,
619 Address expressions_top,
620 uint32_t expressions_size,
621 DeoptimizedFrameInfo* info) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000622 ASSERT_EQ(DEBUGGER, bailout_type_);
Ben Murdochc7cc0282012-03-05 14:35:55 +0000623 Address parameters_bottom = parameters_top + parameters_size;
624 Address expressions_bottom = expressions_top + expressions_size;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000625 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
626 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
627
628 // Check of the heap number to materialize actually belong to the frame
629 // being extracted.
630 Address slot = d.slot_address();
Ben Murdochc7cc0282012-03-05 14:35:55 +0000631 if (parameters_top <= slot && slot < parameters_bottom) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000632 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
Ben Murdochc7cc0282012-03-05 14:35:55 +0000633
634 int index = (info->parameters_count() - 1) -
635 static_cast<int>(slot - parameters_top) / kPointerSize;
636
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000637 if (FLAG_trace_deopt) {
638 PrintF("Materializing a new heap number %p [%e] in slot %p"
Ben Murdochc7cc0282012-03-05 14:35:55 +0000639 "for parameter slot #%d\n",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000640 reinterpret_cast<void*>(*num),
641 d.value(),
642 d.slot_address(),
643 index);
644 }
Ben Murdochc7cc0282012-03-05 14:35:55 +0000645
646 info->SetParameter(index, *num);
647 } else if (expressions_top <= slot && slot < expressions_bottom) {
648 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
649
650 int index = info->expression_count() - 1 -
651 static_cast<int>(slot - expressions_top) / kPointerSize;
652
653 if (FLAG_trace_deopt) {
654 PrintF("Materializing a new heap number %p [%e] in slot %p"
655 "for expression slot #%d\n",
656 reinterpret_cast<void*>(*num),
657 d.value(),
658 d.slot_address(),
659 index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000660 }
Ben Murdochc7cc0282012-03-05 14:35:55 +0000661
662 info->SetExpression(index, *num);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000663 }
664 }
665}
666#endif
667
668
Ben Murdochb0fe1622011-05-05 13:52:32 +0100669void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
670 int frame_index,
671 unsigned output_offset) {
672 disasm::NameConverter converter;
673 // A GC-safe temporary placeholder that we can put in the output frame.
674 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
675
676 // Ignore commands marked as duplicate and act on the first non-duplicate.
677 Translation::Opcode opcode =
678 static_cast<Translation::Opcode>(iterator->Next());
679 while (opcode == Translation::DUPLICATE) {
680 opcode = static_cast<Translation::Opcode>(iterator->Next());
681 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
682 opcode = static_cast<Translation::Opcode>(iterator->Next());
683 }
684
685 switch (opcode) {
686 case Translation::BEGIN:
Ben Murdochc7cc0282012-03-05 14:35:55 +0000687 case Translation::JS_FRAME:
688 case Translation::ARGUMENTS_ADAPTOR_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100689 case Translation::DUPLICATE:
690 UNREACHABLE();
691 return;
692
693 case Translation::REGISTER: {
694 int input_reg = iterator->Next();
695 intptr_t input_value = input_->GetRegister(input_reg);
696 if (FLAG_trace_deopt) {
697 PrintF(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000698 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100699 output_[frame_index]->GetTop() + output_offset,
700 output_offset,
701 input_value,
702 converter.NameOfCPURegister(input_reg));
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_REGISTER: {
711 int input_reg = iterator->Next();
712 intptr_t value = input_->GetRegister(input_reg);
713 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100714 if (FLAG_trace_deopt) {
715 PrintF(
716 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
717 output_[frame_index]->GetTop() + output_offset,
718 output_offset,
719 value,
720 converter.NameOfCPURegister(input_reg),
721 is_smi ? "smi" : "heap number");
722 }
723 if (is_smi) {
724 intptr_t tagged_value =
725 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
726 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
727 } else {
728 // We save the untagged value on the side and store a GC-safe
729 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100730 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
731 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100732 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
733 }
734 return;
735 }
736
737 case Translation::DOUBLE_REGISTER: {
738 int input_reg = iterator->Next();
739 double value = input_->GetDoubleRegister(input_reg);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100740 if (FLAG_trace_deopt) {
741 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
742 output_[frame_index]->GetTop() + output_offset,
743 output_offset,
744 value,
745 DoubleRegister::AllocationIndexToString(input_reg));
746 }
747 // We save the untagged value on the side and store a GC-safe
748 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100749 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100750 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
751 return;
752 }
753
754 case Translation::STACK_SLOT: {
755 int input_slot_index = iterator->Next();
756 unsigned input_offset =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000757 input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100758 intptr_t input_value = input_->GetFrameSlot(input_offset);
759 if (FLAG_trace_deopt) {
760 PrintF(" 0x%08" V8PRIxPTR ": ",
761 output_[frame_index]->GetTop() + output_offset);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000762 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100763 output_offset,
764 input_value,
765 input_offset);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000766 reinterpret_cast<Object*>(input_value)->ShortPrint();
767 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100768 }
769 output_[frame_index]->SetFrameSlot(output_offset, input_value);
770 return;
771 }
772
773 case Translation::INT32_STACK_SLOT: {
774 int input_slot_index = iterator->Next();
775 unsigned input_offset =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000776 input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100777 intptr_t value = input_->GetFrameSlot(input_offset);
778 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100779 if (FLAG_trace_deopt) {
780 PrintF(" 0x%08" V8PRIxPTR ": ",
781 output_[frame_index]->GetTop() + output_offset);
782 PrintF("[top + %d] <- %" V8PRIdPTR " ; [esp + %d] (%s)\n",
783 output_offset,
784 value,
785 input_offset,
786 is_smi ? "smi" : "heap number");
787 }
788 if (is_smi) {
789 intptr_t tagged_value =
790 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
791 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
792 } else {
793 // We save the untagged value on the side and store a GC-safe
794 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100795 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
796 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100797 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
798 }
799 return;
800 }
801
802 case Translation::DOUBLE_STACK_SLOT: {
803 int input_slot_index = iterator->Next();
804 unsigned input_offset =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000805 input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100806 double value = input_->GetDoubleFrameSlot(input_offset);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100807 if (FLAG_trace_deopt) {
808 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
809 output_[frame_index]->GetTop() + output_offset,
810 output_offset,
811 value,
812 input_offset);
813 }
814 // We save the untagged value on the side and store a GC-safe
815 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100816 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100817 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
818 return;
819 }
820
821 case Translation::LITERAL: {
822 Object* literal = ComputeLiteral(iterator->Next());
823 if (FLAG_trace_deopt) {
824 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
825 output_[frame_index]->GetTop() + output_offset,
826 output_offset);
827 literal->ShortPrint();
828 PrintF(" ; literal\n");
829 }
830 intptr_t value = reinterpret_cast<intptr_t>(literal);
831 output_[frame_index]->SetFrameSlot(output_offset, value);
832 return;
833 }
834
835 case Translation::ARGUMENTS_OBJECT: {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100836 // Use the arguments marker value as a sentinel and fill in the arguments
837 // object after the deoptimized frame is built.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100838 ASSERT(frame_index == 0); // Only supported for first frame.
839 if (FLAG_trace_deopt) {
840 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
841 output_[frame_index]->GetTop() + output_offset,
842 output_offset);
Steve Block44f0eee2011-05-26 01:26:41 +0100843 isolate_->heap()->arguments_marker()->ShortPrint();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100844 PrintF(" ; arguments object\n");
845 }
Steve Block44f0eee2011-05-26 01:26:41 +0100846 intptr_t value = reinterpret_cast<intptr_t>(
847 isolate_->heap()->arguments_marker());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100848 output_[frame_index]->SetFrameSlot(output_offset, value);
849 return;
850 }
851 }
852}
853
854
855bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
856 int* input_offset) {
857 disasm::NameConverter converter;
858 FrameDescription* output = output_[0];
859
860 // The input values are all part of the unoptimized frame so they
861 // are all tagged pointers.
862 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
863 Object* input_object = reinterpret_cast<Object*>(input_value);
864
865 Translation::Opcode opcode =
866 static_cast<Translation::Opcode>(iterator->Next());
867 bool duplicate = (opcode == Translation::DUPLICATE);
868 if (duplicate) {
869 opcode = static_cast<Translation::Opcode>(iterator->Next());
870 }
871
872 switch (opcode) {
873 case Translation::BEGIN:
Ben Murdochc7cc0282012-03-05 14:35:55 +0000874 case Translation::JS_FRAME:
875 case Translation::ARGUMENTS_ADAPTOR_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100876 case Translation::DUPLICATE:
877 UNREACHABLE(); // Malformed input.
878 return false;
879
880 case Translation::REGISTER: {
881 int output_reg = iterator->Next();
882 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100883 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100884 converter.NameOfCPURegister(output_reg),
885 input_value,
886 *input_offset);
887 }
888 output->SetRegister(output_reg, input_value);
889 break;
890 }
891
892 case Translation::INT32_REGISTER: {
893 // Abort OSR if we don't have a number.
894 if (!input_object->IsNumber()) return false;
895
896 int output_reg = iterator->Next();
897 int int32_value = input_object->IsSmi()
898 ? Smi::cast(input_object)->value()
899 : FastD2I(input_object->Number());
900 // Abort the translation if the conversion lost information.
901 if (!input_object->IsSmi() &&
902 FastI2D(int32_value) != input_object->Number()) {
903 if (FLAG_trace_osr) {
904 PrintF("**** %g could not be converted to int32 ****\n",
905 input_object->Number());
906 }
907 return false;
908 }
909 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100910 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100911 converter.NameOfCPURegister(output_reg),
912 int32_value,
913 *input_offset);
914 }
915 output->SetRegister(output_reg, int32_value);
916 break;
917 }
918
919 case Translation::DOUBLE_REGISTER: {
920 // Abort OSR if we don't have a number.
921 if (!input_object->IsNumber()) return false;
922
923 int output_reg = iterator->Next();
924 double double_value = input_object->Number();
925 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100926 PrintF(" %s <- %g (double) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100927 DoubleRegister::AllocationIndexToString(output_reg),
928 double_value,
929 *input_offset);
930 }
931 output->SetDoubleRegister(output_reg, double_value);
932 break;
933 }
934
935 case Translation::STACK_SLOT: {
936 int output_index = iterator->Next();
937 unsigned output_offset =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000938 output->GetOffsetFromSlotIndex(output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100939 if (FLAG_trace_osr) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000940 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100941 output_offset,
942 input_value,
943 *input_offset);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000944 reinterpret_cast<Object*>(input_value)->ShortPrint();
945 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100946 }
947 output->SetFrameSlot(output_offset, input_value);
948 break;
949 }
950
951 case Translation::INT32_STACK_SLOT: {
952 // Abort OSR if we don't have a number.
953 if (!input_object->IsNumber()) return false;
954
955 int output_index = iterator->Next();
956 unsigned output_offset =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000957 output->GetOffsetFromSlotIndex(output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100958 int int32_value = input_object->IsSmi()
959 ? Smi::cast(input_object)->value()
960 : DoubleToInt32(input_object->Number());
961 // Abort the translation if the conversion lost information.
962 if (!input_object->IsSmi() &&
963 FastI2D(int32_value) != input_object->Number()) {
964 if (FLAG_trace_osr) {
965 PrintF("**** %g could not be converted to int32 ****\n",
966 input_object->Number());
967 }
968 return false;
969 }
970 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100971 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100972 output_offset,
973 int32_value,
974 *input_offset);
975 }
976 output->SetFrameSlot(output_offset, int32_value);
977 break;
978 }
979
980 case Translation::DOUBLE_STACK_SLOT: {
981 static const int kLowerOffset = 0 * kPointerSize;
982 static const int kUpperOffset = 1 * kPointerSize;
983
984 // Abort OSR if we don't have a number.
985 if (!input_object->IsNumber()) return false;
986
987 int output_index = iterator->Next();
988 unsigned output_offset =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000989 output->GetOffsetFromSlotIndex(output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100990 double double_value = input_object->Number();
991 uint64_t int_value = BitCast<uint64_t, double>(double_value);
992 int32_t lower = static_cast<int32_t>(int_value);
993 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
994 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100995 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100996 output_offset + kUpperOffset,
997 upper,
998 double_value,
999 *input_offset);
Steve Block1e0659c2011-05-24 12:43:12 +01001000 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001001 output_offset + kLowerOffset,
1002 lower,
1003 double_value,
1004 *input_offset);
1005 }
1006 output->SetFrameSlot(output_offset + kLowerOffset, lower);
1007 output->SetFrameSlot(output_offset + kUpperOffset, upper);
1008 break;
1009 }
1010
1011 case Translation::LITERAL: {
1012 // Just ignore non-materialized literals.
1013 iterator->Next();
1014 break;
1015 }
1016
1017 case Translation::ARGUMENTS_OBJECT: {
1018 // Optimized code assumes that the argument object has not been
1019 // materialized and so bypasses it when doing arguments access.
1020 // We should have bailed out before starting the frame
1021 // translation.
1022 UNREACHABLE();
1023 return false;
1024 }
1025 }
1026
1027 if (!duplicate) *input_offset -= kPointerSize;
1028 return true;
1029}
1030
1031
Steve Block1e0659c2011-05-24 12:43:12 +01001032void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
1033 Code* check_code,
1034 Code* replacement_code) {
1035 // Iterate over the stack check table and patch every stack check
1036 // call to an unconditional call to the replacement code.
1037 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1038 Address stack_check_cursor = unoptimized_code->instruction_start() +
1039 unoptimized_code->stack_check_table_offset();
1040 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1041 stack_check_cursor += kIntSize;
1042 for (uint32_t i = 0; i < table_length; ++i) {
1043 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1044 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001045 PatchStackCheckCodeAt(unoptimized_code,
1046 pc_after,
1047 check_code,
1048 replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +01001049 stack_check_cursor += 2 * kIntSize;
1050 }
1051}
1052
1053
1054void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
1055 Code* check_code,
1056 Code* replacement_code) {
1057 // Iterate over the stack check table and revert the patched
1058 // stack check calls.
1059 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1060 Address stack_check_cursor = unoptimized_code->instruction_start() +
1061 unoptimized_code->stack_check_table_offset();
1062 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1063 stack_check_cursor += kIntSize;
1064 for (uint32_t i = 0; i < table_length; ++i) {
1065 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1066 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001067 RevertStackCheckCodeAt(unoptimized_code,
1068 pc_after,
1069 check_code,
1070 replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +01001071 stack_check_cursor += 2 * kIntSize;
1072 }
1073}
1074
1075
Ben Murdochb0fe1622011-05-05 13:52:32 +01001076unsigned Deoptimizer::ComputeInputFrameSize() const {
1077 unsigned fixed_size = ComputeFixedSize(function_);
1078 // The fp-to-sp delta already takes the context and the function
1079 // into account so we have to avoid double counting them (-2).
1080 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
1081#ifdef DEBUG
1082 if (bailout_type_ == OSR) {
1083 // TODO(kasperl): It would be nice if we could verify that the
1084 // size matches with the stack height we can compute based on the
1085 // environment at the OSR entry. The code for that his built into
1086 // the DoComputeOsrOutputFrame function for now.
1087 } else {
1088 unsigned stack_slots = optimized_code_->stack_slots();
1089 unsigned outgoing_size = ComputeOutgoingArgumentSize();
1090 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
1091 }
1092#endif
1093 return result;
1094}
1095
1096
1097unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
1098 // The fixed part of the frame consists of the return address, frame
1099 // pointer, function, context, and all the incoming arguments.
Ben Murdochc7cc0282012-03-05 14:35:55 +00001100 return ComputeIncomingArgumentSize(function) +
1101 StandardFrameConstants::kFixedFrameSize;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001102}
1103
1104
1105unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
1106 // The incoming arguments is the values for formal parameters and
1107 // the receiver. Every slot contains a pointer.
1108 unsigned arguments = function->shared()->formal_parameter_count() + 1;
1109 return arguments * kPointerSize;
1110}
1111
1112
1113unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
1114 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1115 optimized_code_->deoptimization_data());
1116 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
1117 return height * kPointerSize;
1118}
1119
1120
1121Object* Deoptimizer::ComputeLiteral(int index) const {
1122 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1123 optimized_code_->deoptimization_data());
1124 FixedArray* literals = data->LiteralArray();
1125 return literals->get(index);
1126}
1127
1128
Ben Murdoch8b112d22011-06-08 16:22:53 +01001129void Deoptimizer::AddDoubleValue(intptr_t slot_address,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001130 double value) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001131 HeapNumberMaterializationDescriptor value_desc(
1132 reinterpret_cast<Address>(slot_address), value);
1133 deferred_heap_numbers_.Add(value_desc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001134}
1135
1136
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001137MemoryChunk* Deoptimizer::CreateCode(BailoutType type) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001138 // We cannot run this if the serializer is enabled because this will
1139 // cause us to emit relocation information for the external
1140 // references. This is fine because the deoptimizer's code section
1141 // isn't meant to be serialized at all.
1142 ASSERT(!Serializer::enabled());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001143
Ben Murdoch8b112d22011-06-08 16:22:53 +01001144 MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
Steve Block44f0eee2011-05-26 01:26:41 +01001145 masm.set_emit_debug_code(false);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001146 GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
1147 CodeDesc desc;
1148 masm.GetCode(&desc);
1149 ASSERT(desc.reloc_size == 0);
1150
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001151 MemoryChunk* chunk =
1152 Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
1153 EXECUTABLE,
1154 NULL);
1155 ASSERT(chunk->area_size() >= desc.instr_size);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001156 if (chunk == NULL) {
1157 V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
1158 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001159 memcpy(chunk->area_start(), desc.buffer, desc.instr_size);
1160 CPU::FlushICache(chunk->area_start(), desc.instr_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001161 return chunk;
1162}
1163
1164
1165Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001166 DeoptimizingCodeListNode* node =
1167 Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001168 while (node != NULL) {
1169 if (node->code()->contains(addr)) return *node->code();
1170 node = node->next();
1171 }
1172 return NULL;
1173}
1174
1175
1176void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
Steve Block44f0eee2011-05-26 01:26:41 +01001177 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
1178 ASSERT(data->deoptimizing_code_list_ != NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001179 // Run through the code objects to find this one and remove it.
1180 DeoptimizingCodeListNode* prev = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01001181 DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001182 while (current != NULL) {
1183 if (*current->code() == code) {
1184 // Unlink from list. If prev is NULL we are looking at the first element.
1185 if (prev == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001186 data->deoptimizing_code_list_ = current->next();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001187 } else {
1188 prev->set_next(current->next());
1189 }
1190 delete current;
1191 return;
1192 }
1193 // Move to next in list.
1194 prev = current;
1195 current = current->next();
1196 }
1197 // Deoptimizing code is removed through weak callback. Each object is expected
1198 // to be removed once and only once.
1199 UNREACHABLE();
1200}
1201
1202
1203FrameDescription::FrameDescription(uint32_t frame_size,
1204 JSFunction* function)
1205 : frame_size_(frame_size),
1206 function_(function),
1207 top_(kZapUint32),
1208 pc_(kZapUint32),
1209 fp_(kZapUint32) {
1210 // Zap all the registers.
1211 for (int r = 0; r < Register::kNumRegisters; r++) {
1212 SetRegister(r, kZapUint32);
1213 }
1214
1215 // Zap all the slots.
1216 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
1217 SetFrameSlot(o, kZapUint32);
1218 }
1219}
1220
1221
Ben Murdochc7cc0282012-03-05 14:35:55 +00001222int FrameDescription::ComputeFixedSize() {
1223 return StandardFrameConstants::kFixedFrameSize +
1224 (ComputeParametersCount() + 1) * kPointerSize;
1225}
1226
1227
1228unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001229 if (slot_index >= 0) {
1230 // Local or spill slots. Skip the fixed part of the frame
1231 // including all arguments.
Ben Murdochc7cc0282012-03-05 14:35:55 +00001232 unsigned base = GetFrameSize() - ComputeFixedSize();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001233 return base - ((slot_index + 1) * kPointerSize);
1234 } else {
1235 // Incoming parameter.
Ben Murdochc7cc0282012-03-05 14:35:55 +00001236 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
1237 unsigned base = GetFrameSize() - arg_size;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001238 return base - ((slot_index + 1) * kPointerSize);
1239 }
1240}
1241
1242
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001243int FrameDescription::ComputeParametersCount() {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001244 switch (type_) {
1245 case StackFrame::JAVA_SCRIPT:
1246 return function_->shared()->formal_parameter_count();
1247 case StackFrame::ARGUMENTS_ADAPTOR: {
1248 // Last slot contains number of incomming arguments as a smi.
1249 // Can't use GetExpression(0) because it would cause infinite recursion.
1250 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value();
1251 }
1252 default:
1253 UNREACHABLE();
1254 return 0;
1255 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001256}
1257
1258
Ben Murdochc7cc0282012-03-05 14:35:55 +00001259Object* FrameDescription::GetParameter(int index) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001260 ASSERT(index >= 0);
1261 ASSERT(index < ComputeParametersCount());
1262 // The slot indexes for incoming arguments are negative.
Ben Murdochc7cc0282012-03-05 14:35:55 +00001263 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001264 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1265}
1266
1267
Ben Murdochc7cc0282012-03-05 14:35:55 +00001268unsigned FrameDescription::GetExpressionCount() {
1269 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1270 unsigned size = GetFrameSize() - ComputeFixedSize();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001271 return size / kPointerSize;
1272}
1273
1274
Ben Murdochc7cc0282012-03-05 14:35:55 +00001275Object* FrameDescription::GetExpression(int index) {
1276 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1277 unsigned offset = GetOffsetFromSlotIndex(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001278 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1279}
1280
1281
Ben Murdochb0fe1622011-05-05 13:52:32 +01001282void TranslationBuffer::Add(int32_t value) {
1283 // Encode the sign bit in the least significant bit.
1284 bool is_negative = (value < 0);
1285 uint32_t bits = ((is_negative ? -value : value) << 1) |
1286 static_cast<int32_t>(is_negative);
1287 // Encode the individual bytes using the least significant bit of
1288 // each byte to indicate whether or not more bytes follow.
1289 do {
1290 uint32_t next = bits >> 7;
1291 contents_.Add(((bits << 1) & 0xFF) | (next != 0));
1292 bits = next;
1293 } while (bits != 0);
1294}
1295
1296
1297int32_t TranslationIterator::Next() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001298 // Run through the bytes until we reach one with a least significant
1299 // bit of zero (marks the end).
1300 uint32_t bits = 0;
1301 for (int i = 0; true; i += 7) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001302 ASSERT(HasNext());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001303 uint8_t next = buffer_->get(index_++);
1304 bits |= (next >> 1) << i;
1305 if ((next & 1) == 0) break;
1306 }
1307 // The bits encode the sign in the least significant bit.
1308 bool is_negative = (bits & 1) == 1;
1309 int32_t result = bits >> 1;
1310 return is_negative ? -result : result;
1311}
1312
1313
1314Handle<ByteArray> TranslationBuffer::CreateByteArray() {
1315 int length = contents_.length();
Steve Block44f0eee2011-05-26 01:26:41 +01001316 Handle<ByteArray> result =
1317 Isolate::Current()->factory()->NewByteArray(length, TENURED);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001318 memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
1319 return result;
1320}
1321
1322
Ben Murdochc7cc0282012-03-05 14:35:55 +00001323void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
1324 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME);
1325 buffer_->Add(literal_id);
1326 buffer_->Add(height);
1327}
1328
1329
1330void Translation::BeginJSFrame(int node_id, int literal_id, unsigned height) {
1331 buffer_->Add(JS_FRAME);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001332 buffer_->Add(node_id);
1333 buffer_->Add(literal_id);
1334 buffer_->Add(height);
1335}
1336
1337
1338void Translation::StoreRegister(Register reg) {
1339 buffer_->Add(REGISTER);
1340 buffer_->Add(reg.code());
1341}
1342
1343
1344void Translation::StoreInt32Register(Register reg) {
1345 buffer_->Add(INT32_REGISTER);
1346 buffer_->Add(reg.code());
1347}
1348
1349
1350void Translation::StoreDoubleRegister(DoubleRegister reg) {
1351 buffer_->Add(DOUBLE_REGISTER);
1352 buffer_->Add(DoubleRegister::ToAllocationIndex(reg));
1353}
1354
1355
1356void Translation::StoreStackSlot(int index) {
1357 buffer_->Add(STACK_SLOT);
1358 buffer_->Add(index);
1359}
1360
1361
1362void Translation::StoreInt32StackSlot(int index) {
1363 buffer_->Add(INT32_STACK_SLOT);
1364 buffer_->Add(index);
1365}
1366
1367
1368void Translation::StoreDoubleStackSlot(int index) {
1369 buffer_->Add(DOUBLE_STACK_SLOT);
1370 buffer_->Add(index);
1371}
1372
1373
1374void Translation::StoreLiteral(int literal_id) {
1375 buffer_->Add(LITERAL);
1376 buffer_->Add(literal_id);
1377}
1378
1379
1380void Translation::StoreArgumentsObject() {
1381 buffer_->Add(ARGUMENTS_OBJECT);
1382}
1383
1384
1385void Translation::MarkDuplicate() {
1386 buffer_->Add(DUPLICATE);
1387}
1388
1389
1390int Translation::NumberOfOperandsFor(Opcode opcode) {
1391 switch (opcode) {
1392 case ARGUMENTS_OBJECT:
1393 case DUPLICATE:
1394 return 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001395 case REGISTER:
1396 case INT32_REGISTER:
1397 case DOUBLE_REGISTER:
1398 case STACK_SLOT:
1399 case INT32_STACK_SLOT:
1400 case DOUBLE_STACK_SLOT:
1401 case LITERAL:
1402 return 1;
Ben Murdochc7cc0282012-03-05 14:35:55 +00001403 case BEGIN:
1404 case ARGUMENTS_ADAPTOR_FRAME:
1405 return 2;
1406 case JS_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +01001407 return 3;
1408 }
1409 UNREACHABLE();
1410 return -1;
1411}
1412
1413
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001414#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001415
1416const char* Translation::StringFor(Opcode opcode) {
1417 switch (opcode) {
1418 case BEGIN:
1419 return "BEGIN";
Ben Murdochc7cc0282012-03-05 14:35:55 +00001420 case JS_FRAME:
1421 return "JS_FRAME";
1422 case ARGUMENTS_ADAPTOR_FRAME:
1423 return "ARGUMENTS_ADAPTOR_FRAME";
Ben Murdochb0fe1622011-05-05 13:52:32 +01001424 case REGISTER:
1425 return "REGISTER";
1426 case INT32_REGISTER:
1427 return "INT32_REGISTER";
1428 case DOUBLE_REGISTER:
1429 return "DOUBLE_REGISTER";
1430 case STACK_SLOT:
1431 return "STACK_SLOT";
1432 case INT32_STACK_SLOT:
1433 return "INT32_STACK_SLOT";
1434 case DOUBLE_STACK_SLOT:
1435 return "DOUBLE_STACK_SLOT";
1436 case LITERAL:
1437 return "LITERAL";
1438 case ARGUMENTS_OBJECT:
1439 return "ARGUMENTS_OBJECT";
1440 case DUPLICATE:
1441 return "DUPLICATE";
1442 }
1443 UNREACHABLE();
1444 return "";
1445}
1446
1447#endif
1448
1449
1450DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001451 GlobalHandles* global_handles = Isolate::Current()->global_handles();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001452 // Globalize the code object and make it weak.
Steve Block44f0eee2011-05-26 01:26:41 +01001453 code_ = Handle<Code>::cast(global_handles->Create(code));
1454 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
1455 this,
1456 Deoptimizer::HandleWeakDeoptimizedCode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001457}
1458
1459
1460DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
Steve Block44f0eee2011-05-26 01:26:41 +01001461 GlobalHandles* global_handles = Isolate::Current()->global_handles();
1462 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001463}
1464
1465
Ben Murdoch8b112d22011-06-08 16:22:53 +01001466// We can't intermix stack decoding and allocations because
1467// deoptimization infrastracture is not GC safe.
1468// Thus we build a temporary structure in malloced space.
1469SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
1470 DeoptimizationInputData* data,
1471 JavaScriptFrame* frame) {
1472 Translation::Opcode opcode =
1473 static_cast<Translation::Opcode>(iterator->Next());
1474
1475 switch (opcode) {
1476 case Translation::BEGIN:
Ben Murdochc7cc0282012-03-05 14:35:55 +00001477 case Translation::JS_FRAME:
1478 case Translation::ARGUMENTS_ADAPTOR_FRAME:
Ben Murdoch8b112d22011-06-08 16:22:53 +01001479 // Peeled off before getting here.
1480 break;
1481
1482 case Translation::ARGUMENTS_OBJECT:
1483 // This can be only emitted for local slots not for argument slots.
1484 break;
1485
1486 case Translation::REGISTER:
1487 case Translation::INT32_REGISTER:
1488 case Translation::DOUBLE_REGISTER:
1489 case Translation::DUPLICATE:
1490 // We are at safepoint which corresponds to call. All registers are
1491 // saved by caller so there would be no live registers at this
1492 // point. Thus these translation commands should not be used.
1493 break;
1494
1495 case Translation::STACK_SLOT: {
1496 int slot_index = iterator->Next();
1497 Address slot_addr = SlotAddress(frame, slot_index);
1498 return SlotRef(slot_addr, SlotRef::TAGGED);
1499 }
1500
1501 case Translation::INT32_STACK_SLOT: {
1502 int slot_index = iterator->Next();
1503 Address slot_addr = SlotAddress(frame, slot_index);
1504 return SlotRef(slot_addr, SlotRef::INT32);
1505 }
1506
1507 case Translation::DOUBLE_STACK_SLOT: {
1508 int slot_index = iterator->Next();
1509 Address slot_addr = SlotAddress(frame, slot_index);
1510 return SlotRef(slot_addr, SlotRef::DOUBLE);
1511 }
1512
1513 case Translation::LITERAL: {
1514 int literal_index = iterator->Next();
1515 return SlotRef(data->LiteralArray()->get(literal_index));
1516 }
1517 }
1518
1519 UNREACHABLE();
1520 return SlotRef();
1521}
1522
1523
Ben Murdochc7cc0282012-03-05 14:35:55 +00001524void SlotRef::ComputeSlotsForArguments(Vector<SlotRef>* args_slots,
1525 TranslationIterator* it,
1526 DeoptimizationInputData* data,
1527 JavaScriptFrame* frame) {
1528 // Process the translation commands for the arguments.
1529
1530 // Skip the translation command for the receiver.
1531 it->Skip(Translation::NumberOfOperandsFor(
1532 static_cast<Translation::Opcode>(it->Next())));
1533
1534 // Compute slots for arguments.
1535 for (int i = 0; i < args_slots->length(); ++i) {
1536 (*args_slots)[i] = ComputeSlotForNextArgument(it, data, frame);
1537 }
1538}
1539
1540
1541Vector<SlotRef> SlotRef::ComputeSlotMappingForArguments(
1542 JavaScriptFrame* frame,
1543 int inlined_jsframe_index,
1544 int formal_parameter_count) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001545 AssertNoAllocation no_gc;
1546 int deopt_index = AstNode::kNoNumber;
1547 DeoptimizationInputData* data =
1548 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
1549 TranslationIterator it(data->TranslationByteArray(),
1550 data->TranslationIndex(deopt_index)->value());
1551 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1552 ASSERT(opcode == Translation::BEGIN);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001553 it.Next(); // Drop frame count.
1554 int jsframe_count = it.Next();
1555 USE(jsframe_count);
1556 ASSERT(jsframe_count > inlined_jsframe_index);
1557 int jsframes_to_skip = inlined_jsframe_index;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001558 while (true) {
1559 opcode = static_cast<Translation::Opcode>(it.Next());
Ben Murdochc7cc0282012-03-05 14:35:55 +00001560 if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) {
1561 if (jsframes_to_skip == 0) {
1562 ASSERT(Translation::NumberOfOperandsFor(opcode) == 2);
1563
1564 it.Skip(1); // literal id
1565 int height = it.Next();
1566
1567 // We reached the arguments adaptor frame corresponding to the
1568 // inlined function in question. Number of arguments is height - 1.
1569 Vector<SlotRef> args_slots =
1570 Vector<SlotRef>::New(height - 1); // Minus receiver.
1571 ComputeSlotsForArguments(&args_slots, &it, data, frame);
1572 return args_slots;
1573 }
1574 } else if (opcode == Translation::JS_FRAME) {
1575 if (jsframes_to_skip == 0) {
1576 // Skip over operands to advance to the next opcode.
1577 it.Skip(Translation::NumberOfOperandsFor(opcode));
1578
Ben Murdoch8b112d22011-06-08 16:22:53 +01001579 // We reached the frame corresponding to the inlined function
1580 // in question. Process the translation commands for the
Ben Murdochc7cc0282012-03-05 14:35:55 +00001581 // arguments. Number of arguments is equal to the number of
1582 // format parameter count.
1583 Vector<SlotRef> args_slots =
1584 Vector<SlotRef>::New(formal_parameter_count);
1585 ComputeSlotsForArguments(&args_slots, &it, data, frame);
1586 return args_slots;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001587 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00001588 jsframes_to_skip--;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001589 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00001590
1591 // Skip over operands to advance to the next opcode.
1592 it.Skip(Translation::NumberOfOperandsFor(opcode));
Ben Murdoch8b112d22011-06-08 16:22:53 +01001593 }
1594
1595 UNREACHABLE();
Ben Murdochc7cc0282012-03-05 14:35:55 +00001596 return Vector<SlotRef>();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001597}
1598
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001599#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch8b112d22011-06-08 16:22:53 +01001600
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001601DeoptimizedFrameInfo::DeoptimizedFrameInfo(
Ben Murdochc7cc0282012-03-05 14:35:55 +00001602 Deoptimizer* deoptimizer, int frame_index, bool has_arguments_adaptor) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001603 FrameDescription* output_frame = deoptimizer->output_[frame_index];
1604 SetFunction(output_frame->GetFunction());
Ben Murdochc7cc0282012-03-05 14:35:55 +00001605 expression_count_ = output_frame->GetExpressionCount();
1606 expression_stack_ = new Object*[expression_count_];
1607 for (int i = 0; i < expression_count_; i++) {
1608 SetExpression(i, output_frame->GetExpression(i));
1609 }
1610
1611 if (has_arguments_adaptor) {
1612 output_frame = deoptimizer->output_[frame_index - 1];
1613 ASSERT(output_frame->GetFrameType() == StackFrame::ARGUMENTS_ADAPTOR);
1614 }
1615
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001616 parameters_count_ = output_frame->ComputeParametersCount();
1617 parameters_ = new Object*[parameters_count_];
1618 for (int i = 0; i < parameters_count_; i++) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001619 SetParameter(i, output_frame->GetParameter(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001620 }
1621}
1622
1623
1624DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
1625 delete[] expression_stack_;
1626 delete[] parameters_;
1627}
1628
1629void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
1630 v->VisitPointer(BitCast<Object**>(&function_));
1631 v->VisitPointers(parameters_, parameters_ + parameters_count_);
1632 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
1633}
1634
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001635#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001636
Ben Murdochb0fe1622011-05-05 13:52:32 +01001637} } // namespace v8::internal