blob: 2a30ddd3dab4c743a72ef4a251f559dd294a2b48 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// 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 Murdoch3ef787d2012-04-12 10:51:47 +010055 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 Murdoch3ef787d2012-04-12 10:51:47 +010060 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 Murdoch3ef787d2012-04-12 10:51:47 +010076// 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 Murdoch3ef787d2012-04-12 10:51:47 +0100107
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 Murdoch3ef787d2012-04-12 10:51:47 +0100127 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 Murdoch3ef787d2012-04-12 10:51:47 +0100163 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
173 int construct_offset = has_arguments_adaptor ? 2 : 1;
174 bool has_construct_stub =
175 frame_index >= construct_offset &&
176 deoptimizer->output_[frame_index - construct_offset]->GetFrameType() ==
177 StackFrame::CONSTRUCT;
178
179 DeoptimizedFrameInfo* info = new DeoptimizedFrameInfo(deoptimizer,
180 frame_index,
181 has_arguments_adaptor,
182 has_construct_stub);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000183 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
184
185 // Get the "simulated" top and size for the requested frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100186 FrameDescription* parameters_frame =
187 deoptimizer->output_[
188 has_arguments_adaptor ? (frame_index - 1) : frame_index];
189
190 uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize;
191 Address parameters_top = reinterpret_cast<Address>(
192 parameters_frame->GetTop() + (parameters_frame->GetFrameSize() -
193 parameters_size));
194
195 uint32_t expressions_size = info->expression_count() * kPointerSize;
196 Address expressions_top = reinterpret_cast<Address>(
197 deoptimizer->output_[frame_index]->GetTop());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000198
199 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
200 deoptimizer->DeleteFrameDescriptions();
201
202 // Allocate a heap number for the doubles belonging to this frame.
203 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100204 parameters_top, parameters_size, expressions_top, expressions_size, info);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000205
206 // Finished using the deoptimizer instance.
207 delete deoptimizer;
208
209 return info;
210}
211
212
213void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
214 Isolate* isolate) {
215 ASSERT(isolate == Isolate::Current());
216 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
217 delete info;
218 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
219}
220#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100221
222void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
223 int count,
224 BailoutType type) {
225 TableEntryGenerator generator(masm, type, count);
226 generator.Generate();
227}
228
229
230class DeoptimizingVisitor : public OptimizedFunctionVisitor {
231 public:
232 virtual void EnterContext(Context* context) {
233 if (FLAG_trace_deopt) {
234 PrintF("[deoptimize context: %" V8PRIxPTR "]\n",
235 reinterpret_cast<intptr_t>(context));
236 }
237 }
238
239 virtual void VisitFunction(JSFunction* function) {
240 Deoptimizer::DeoptimizeFunction(function);
241 }
242
243 virtual void LeaveContext(Context* context) {
244 context->ClearOptimizedFunctions();
245 }
246};
247
248
249void Deoptimizer::DeoptimizeAll() {
250 AssertNoAllocation no_allocation;
251
252 if (FLAG_trace_deopt) {
253 PrintF("[deoptimize all contexts]\n");
254 }
255
256 DeoptimizingVisitor visitor;
257 VisitAllOptimizedFunctions(&visitor);
258}
259
260
261void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
262 AssertNoAllocation no_allocation;
263
264 DeoptimizingVisitor visitor;
265 VisitAllOptimizedFunctionsForGlobalObject(object, &visitor);
266}
267
268
269void Deoptimizer::VisitAllOptimizedFunctionsForContext(
270 Context* context, OptimizedFunctionVisitor* visitor) {
271 AssertNoAllocation no_allocation;
272
273 ASSERT(context->IsGlobalContext());
274
275 visitor->EnterContext(context);
276 // Run through the list of optimized functions and deoptimize them.
277 Object* element = context->OptimizedFunctionsListHead();
278 while (!element->IsUndefined()) {
279 JSFunction* element_function = JSFunction::cast(element);
280 // Get the next link before deoptimizing as deoptimizing will clear the
281 // next link.
282 element = element_function->next_function_link();
283 visitor->VisitFunction(element_function);
284 }
285 visitor->LeaveContext(context);
286}
287
288
289void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
290 JSObject* object, OptimizedFunctionVisitor* visitor) {
291 AssertNoAllocation no_allocation;
292
293 if (object->IsJSGlobalProxy()) {
294 Object* proto = object->GetPrototype();
295 ASSERT(proto->IsJSGlobalObject());
296 VisitAllOptimizedFunctionsForContext(
297 GlobalObject::cast(proto)->global_context(), visitor);
298 } else if (object->IsGlobalObject()) {
299 VisitAllOptimizedFunctionsForContext(
300 GlobalObject::cast(object)->global_context(), visitor);
301 }
302}
303
304
305void Deoptimizer::VisitAllOptimizedFunctions(
306 OptimizedFunctionVisitor* visitor) {
307 AssertNoAllocation no_allocation;
308
309 // Run through the list of all global contexts and deoptimize.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100310 Object* context = Isolate::Current()->heap()->global_contexts_list();
311 while (!context->IsUndefined()) {
312 // GC can happen when the context is not fully initialized,
313 // so the global field of the context can be undefined.
314 Object* global = Context::cast(context)->get(Context::GLOBAL_INDEX);
315 if (!global->IsUndefined()) {
316 VisitAllOptimizedFunctionsForGlobalObject(JSObject::cast(global),
317 visitor);
318 }
319 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100320 }
321}
322
323
324void Deoptimizer::HandleWeakDeoptimizedCode(
325 v8::Persistent<v8::Value> obj, void* data) {
326 DeoptimizingCodeListNode* node =
327 reinterpret_cast<DeoptimizingCodeListNode*>(data);
328 RemoveDeoptimizingCode(*node->code());
329#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100330 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100331 while (node != NULL) {
332 ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
333 node = node->next();
334 }
335#endif
336}
337
338
Ben Murdoch8b112d22011-06-08 16:22:53 +0100339void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100340 deoptimizer->DoComputeOutputFrames();
341}
342
343
Steve Block44f0eee2011-05-26 01:26:41 +0100344Deoptimizer::Deoptimizer(Isolate* isolate,
345 JSFunction* function,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100346 BailoutType type,
347 unsigned bailout_id,
348 Address from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000349 int fp_to_sp_delta,
350 Code* optimized_code)
Steve Block44f0eee2011-05-26 01:26:41 +0100351 : isolate_(isolate),
352 function_(function),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100353 bailout_id_(bailout_id),
354 bailout_type_(type),
355 from_(from),
356 fp_to_sp_delta_(fp_to_sp_delta),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000357 input_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100358 output_count_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100359 jsframe_count_(0),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100360 output_(NULL),
Ben Murdoch8b112d22011-06-08 16:22:53 +0100361 deferred_heap_numbers_(0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100362 if (FLAG_trace_deopt && type != OSR) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000363 if (type == DEBUGGER) {
364 PrintF("**** DEOPT FOR DEBUGGER: ");
365 } else {
366 PrintF("**** DEOPT: ");
367 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100368 function->PrintName();
369 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
370 bailout_id,
371 reinterpret_cast<intptr_t>(from),
372 fp_to_sp_delta - (2 * kPointerSize));
373 } else if (FLAG_trace_osr && type == OSR) {
374 PrintF("**** OSR: ");
375 function->PrintName();
376 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
377 bailout_id,
378 reinterpret_cast<intptr_t>(from),
379 fp_to_sp_delta - (2 * kPointerSize));
380 }
381 // Find the optimized code.
382 if (type == EAGER) {
383 ASSERT(from == NULL);
384 optimized_code_ = function_->code();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100385 if (FLAG_trace_deopt && FLAG_code_comments) {
386 // Print instruction associated with this bailout.
387 const char* last_comment = NULL;
388 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
389 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
390 for (RelocIterator it(optimized_code_, mask); !it.done(); it.next()) {
391 RelocInfo* info = it.rinfo();
392 if (info->rmode() == RelocInfo::COMMENT) {
393 last_comment = reinterpret_cast<const char*>(info->data());
394 }
395 if (info->rmode() == RelocInfo::RUNTIME_ENTRY) {
396 unsigned id = Deoptimizer::GetDeoptimizationId(
397 info->target_address(), Deoptimizer::EAGER);
398 if (id == bailout_id && last_comment != NULL) {
399 PrintF(" %s\n", last_comment);
400 break;
401 }
402 }
403 }
404 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100405 } else if (type == LAZY) {
406 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
407 ASSERT(optimized_code_ != NULL);
408 } else if (type == OSR) {
409 // The function has already been optimized and we're transitioning
410 // from the unoptimized shared version to the optimized one in the
411 // function. The return address (from) points to unoptimized code.
412 optimized_code_ = function_->code();
413 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
414 ASSERT(!optimized_code_->contains(from));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000415 } else if (type == DEBUGGER) {
416 optimized_code_ = optimized_code;
417 ASSERT(optimized_code_->contains(from));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100418 }
Steve Block44f0eee2011-05-26 01:26:41 +0100419 ASSERT(HEAP->allow_allocation(false));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100420 unsigned size = ComputeInputFrameSize();
421 input_ = new(size) FrameDescription(size, function);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100422 input_->SetFrameType(StackFrame::JAVA_SCRIPT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100423}
424
425
426Deoptimizer::~Deoptimizer() {
427 ASSERT(input_ == NULL && output_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100428}
429
430
431void Deoptimizer::DeleteFrameDescriptions() {
432 delete input_;
433 for (int i = 0; i < output_count_; ++i) {
434 if (output_[i] != input_) delete output_[i];
435 }
436 delete[] output_;
437 input_ = NULL;
438 output_ = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100439 ASSERT(!HEAP->allow_allocation(true));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100440}
441
442
443Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
444 ASSERT(id >= 0);
445 if (id >= kNumberOfEntries) return NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100446 MemoryChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100447 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100448 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100449 if (data->eager_deoptimization_entry_code_ == NULL) {
450 data->eager_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100451 }
Steve Block44f0eee2011-05-26 01:26:41 +0100452 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100453 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100454 if (data->lazy_deoptimization_entry_code_ == NULL) {
455 data->lazy_deoptimization_entry_code_ = CreateCode(type);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100456 }
Steve Block44f0eee2011-05-26 01:26:41 +0100457 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100458 }
459 return
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100460 static_cast<Address>(base->area_start()) + (id * table_entry_size_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100461}
462
463
464int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100465 MemoryChunk* base = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100466 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100467 if (type == EAGER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100468 base = data->eager_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100469 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100470 base = data->lazy_deoptimization_entry_code_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100471 }
472 if (base == NULL ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100473 addr < base->area_start() ||
474 addr >= base->area_start() +
Ben Murdochb0fe1622011-05-05 13:52:32 +0100475 (kNumberOfEntries * table_entry_size_)) {
476 return kNotDeoptimizationEntry;
477 }
478 ASSERT_EQ(0,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100479 static_cast<int>(addr - base->area_start()) % table_entry_size_);
480 return static_cast<int>(addr - base->area_start()) / table_entry_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100481}
482
483
Steve Block9fac8402011-05-12 15:51:54 +0100484int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
485 unsigned id,
486 SharedFunctionInfo* shared) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100487 // TODO(kasperl): For now, we do a simple linear search for the PC
488 // offset associated with the given node id. This should probably be
489 // changed to a binary search.
490 int length = data->DeoptPoints();
491 Smi* smi_id = Smi::FromInt(id);
492 for (int i = 0; i < length; i++) {
493 if (data->AstId(i) == smi_id) {
494 return data->PcAndState(i)->value();
495 }
496 }
497 PrintF("[couldn't find pc offset for node=%u]\n", id);
498 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
499 // Print the source code if available.
500 HeapStringAllocator string_allocator;
501 StringStream stream(&string_allocator);
502 shared->SourceCodePrint(&stream, -1);
503 PrintF("[source:\n%s\n]", *stream.ToCString());
504
505 UNREACHABLE();
506 return -1;
507}
508
509
Steve Block44f0eee2011-05-26 01:26:41 +0100510int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100511 int length = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100512 DeoptimizingCodeListNode* node =
513 isolate->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100514 while (node != NULL) {
515 length++;
516 node = node->next();
517 }
518 return length;
519}
520
521
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100522// We rely on this function not causing a GC. It is called from generated code
523// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100524void Deoptimizer::DoComputeOutputFrames() {
525 if (bailout_type_ == OSR) {
526 DoComputeOsrOutputFrame();
527 return;
528 }
529
530 // Print some helpful diagnostic information.
531 int64_t start = OS::Ticks();
532 if (FLAG_trace_deopt) {
533 PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
534 (bailout_type_ == LAZY ? " (lazy)" : ""),
535 reinterpret_cast<intptr_t>(function_));
536 function_->PrintName();
537 PrintF(" @%d]\n", bailout_id_);
538 }
539
540 // Determine basic deoptimization information. The optimized frame is
541 // described by the input data.
542 DeoptimizationInputData* input_data =
543 DeoptimizationInputData::cast(optimized_code_->deoptimization_data());
544 unsigned node_id = input_data->AstId(bailout_id_)->value();
545 ByteArray* translations = input_data->TranslationByteArray();
546 unsigned translation_index =
547 input_data->TranslationIndex(bailout_id_)->value();
548
549 // Do the input frame to output frame(s) translation.
550 TranslationIterator iterator(translations, translation_index);
551 Translation::Opcode opcode =
552 static_cast<Translation::Opcode>(iterator.Next());
553 ASSERT(Translation::BEGIN == opcode);
554 USE(opcode);
555 // Read the number of output frames and allocate an array for their
556 // descriptions.
557 int count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100558 iterator.Next(); // Drop JS frames count.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100559 ASSERT(output_ == NULL);
560 output_ = new FrameDescription*[count];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100561 for (int i = 0; i < count; ++i) {
562 output_[i] = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100563 }
564 output_count_ = count;
565
566 // Translate each output frame.
567 for (int i = 0; i < count; ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100568 // Read the ast node id, function, and frame height for this output frame.
569 Translation::Opcode opcode =
570 static_cast<Translation::Opcode>(iterator.Next());
571 switch (opcode) {
572 case Translation::JS_FRAME:
573 DoComputeJSFrame(&iterator, i);
574 jsframe_count_++;
575 break;
576 case Translation::ARGUMENTS_ADAPTOR_FRAME:
577 DoComputeArgumentsAdaptorFrame(&iterator, i);
578 break;
579 case Translation::CONSTRUCT_STUB_FRAME:
580 DoComputeConstructStubFrame(&iterator, i);
581 break;
582 default:
583 UNREACHABLE();
584 break;
585 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100586 }
587
588 // Print some helpful diagnostic information.
589 if (FLAG_trace_deopt) {
590 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
591 int index = output_count_ - 1; // Index of the topmost frame.
592 JSFunction* function = output_[index]->GetFunction();
593 PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
594 reinterpret_cast<intptr_t>(function));
595 function->PrintName();
596 PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
597 node_id,
598 output_[index]->GetPc(),
599 FullCodeGenerator::State2String(
600 static_cast<FullCodeGenerator::State>(
601 output_[index]->GetState()->value())),
602 ms);
603 }
604}
605
606
Ben Murdoch8b112d22011-06-08 16:22:53 +0100607void Deoptimizer::MaterializeHeapNumbers() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000608 ASSERT_NE(DEBUGGER, bailout_type_);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100609 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
610 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
611 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
612 if (FLAG_trace_deopt) {
613 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
614 reinterpret_cast<void*>(*num),
615 d.value(),
616 d.slot_address());
617 }
618
619 Memory::Object_at(d.slot_address()) = *num;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100620 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100621}
622
623
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000624#ifdef ENABLE_DEBUGGER_SUPPORT
625void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100626 Address parameters_top,
627 uint32_t parameters_size,
628 Address expressions_top,
629 uint32_t expressions_size,
630 DeoptimizedFrameInfo* info) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000631 ASSERT_EQ(DEBUGGER, bailout_type_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100632 Address parameters_bottom = parameters_top + parameters_size;
633 Address expressions_bottom = expressions_top + expressions_size;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000634 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
635 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
636
637 // Check of the heap number to materialize actually belong to the frame
638 // being extracted.
639 Address slot = d.slot_address();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100640 if (parameters_top <= slot && slot < parameters_bottom) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000641 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100642
643 int index = (info->parameters_count() - 1) -
644 static_cast<int>(slot - parameters_top) / kPointerSize;
645
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000646 if (FLAG_trace_deopt) {
647 PrintF("Materializing a new heap number %p [%e] in slot %p"
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100648 "for parameter slot #%d\n",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000649 reinterpret_cast<void*>(*num),
650 d.value(),
651 d.slot_address(),
652 index);
653 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100654
655 info->SetParameter(index, *num);
656 } else if (expressions_top <= slot && slot < expressions_bottom) {
657 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
658
659 int index = info->expression_count() - 1 -
660 static_cast<int>(slot - expressions_top) / kPointerSize;
661
662 if (FLAG_trace_deopt) {
663 PrintF("Materializing a new heap number %p [%e] in slot %p"
664 "for expression slot #%d\n",
665 reinterpret_cast<void*>(*num),
666 d.value(),
667 d.slot_address(),
668 index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000669 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100670
671 info->SetExpression(index, *num);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000672 }
673 }
674}
675#endif
676
677
Ben Murdochb0fe1622011-05-05 13:52:32 +0100678void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
679 int frame_index,
680 unsigned output_offset) {
681 disasm::NameConverter converter;
682 // A GC-safe temporary placeholder that we can put in the output frame.
683 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
684
685 // Ignore commands marked as duplicate and act on the first non-duplicate.
686 Translation::Opcode opcode =
687 static_cast<Translation::Opcode>(iterator->Next());
688 while (opcode == Translation::DUPLICATE) {
689 opcode = static_cast<Translation::Opcode>(iterator->Next());
690 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
691 opcode = static_cast<Translation::Opcode>(iterator->Next());
692 }
693
694 switch (opcode) {
695 case Translation::BEGIN:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100696 case Translation::JS_FRAME:
697 case Translation::ARGUMENTS_ADAPTOR_FRAME:
698 case Translation::CONSTRUCT_STUB_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100699 case Translation::DUPLICATE:
700 UNREACHABLE();
701 return;
702
703 case Translation::REGISTER: {
704 int input_reg = iterator->Next();
705 intptr_t input_value = input_->GetRegister(input_reg);
706 if (FLAG_trace_deopt) {
707 PrintF(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100708 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100709 output_[frame_index]->GetTop() + output_offset,
710 output_offset,
711 input_value,
712 converter.NameOfCPURegister(input_reg));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100713 reinterpret_cast<Object*>(input_value)->ShortPrint();
714 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715 }
716 output_[frame_index]->SetFrameSlot(output_offset, input_value);
717 return;
718 }
719
720 case Translation::INT32_REGISTER: {
721 int input_reg = iterator->Next();
722 intptr_t value = input_->GetRegister(input_reg);
723 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100724 if (FLAG_trace_deopt) {
725 PrintF(
726 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
727 output_[frame_index]->GetTop() + output_offset,
728 output_offset,
729 value,
730 converter.NameOfCPURegister(input_reg),
731 is_smi ? "smi" : "heap number");
732 }
733 if (is_smi) {
734 intptr_t tagged_value =
735 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
736 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
737 } else {
738 // We save the untagged value on the side and store a GC-safe
739 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100740 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
741 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100742 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
743 }
744 return;
745 }
746
747 case Translation::DOUBLE_REGISTER: {
748 int input_reg = iterator->Next();
749 double value = input_->GetDoubleRegister(input_reg);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100750 if (FLAG_trace_deopt) {
751 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
752 output_[frame_index]->GetTop() + output_offset,
753 output_offset,
754 value,
755 DoubleRegister::AllocationIndexToString(input_reg));
756 }
757 // We save the untagged value on the side and store a GC-safe
758 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100759 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100760 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
761 return;
762 }
763
764 case Translation::STACK_SLOT: {
765 int input_slot_index = iterator->Next();
766 unsigned input_offset =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100767 input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100768 intptr_t input_value = input_->GetFrameSlot(input_offset);
769 if (FLAG_trace_deopt) {
770 PrintF(" 0x%08" V8PRIxPTR ": ",
771 output_[frame_index]->GetTop() + output_offset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100772 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100773 output_offset,
774 input_value,
775 input_offset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100776 reinterpret_cast<Object*>(input_value)->ShortPrint();
777 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100778 }
779 output_[frame_index]->SetFrameSlot(output_offset, input_value);
780 return;
781 }
782
783 case Translation::INT32_STACK_SLOT: {
784 int input_slot_index = iterator->Next();
785 unsigned input_offset =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100786 input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100787 intptr_t value = input_->GetFrameSlot(input_offset);
788 bool is_smi = Smi::IsValid(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100789 if (FLAG_trace_deopt) {
790 PrintF(" 0x%08" V8PRIxPTR ": ",
791 output_[frame_index]->GetTop() + output_offset);
792 PrintF("[top + %d] <- %" V8PRIdPTR " ; [esp + %d] (%s)\n",
793 output_offset,
794 value,
795 input_offset,
796 is_smi ? "smi" : "heap number");
797 }
798 if (is_smi) {
799 intptr_t tagged_value =
800 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
801 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
802 } else {
803 // We save the untagged value on the side and store a GC-safe
804 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100805 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
806 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100807 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
808 }
809 return;
810 }
811
812 case Translation::DOUBLE_STACK_SLOT: {
813 int input_slot_index = iterator->Next();
814 unsigned input_offset =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100815 input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100816 double value = input_->GetDoubleFrameSlot(input_offset);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100817 if (FLAG_trace_deopt) {
818 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
819 output_[frame_index]->GetTop() + output_offset,
820 output_offset,
821 value,
822 input_offset);
823 }
824 // We save the untagged value on the side and store a GC-safe
825 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100826 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100827 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
828 return;
829 }
830
831 case Translation::LITERAL: {
832 Object* literal = ComputeLiteral(iterator->Next());
833 if (FLAG_trace_deopt) {
834 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
835 output_[frame_index]->GetTop() + output_offset,
836 output_offset);
837 literal->ShortPrint();
838 PrintF(" ; literal\n");
839 }
840 intptr_t value = reinterpret_cast<intptr_t>(literal);
841 output_[frame_index]->SetFrameSlot(output_offset, value);
842 return;
843 }
844
845 case Translation::ARGUMENTS_OBJECT: {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100846 // Use the arguments marker value as a sentinel and fill in the arguments
847 // object after the deoptimized frame is built.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100848 if (FLAG_trace_deopt) {
849 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
850 output_[frame_index]->GetTop() + output_offset,
851 output_offset);
Steve Block44f0eee2011-05-26 01:26:41 +0100852 isolate_->heap()->arguments_marker()->ShortPrint();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100853 PrintF(" ; arguments object\n");
854 }
Steve Block44f0eee2011-05-26 01:26:41 +0100855 intptr_t value = reinterpret_cast<intptr_t>(
856 isolate_->heap()->arguments_marker());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100857 output_[frame_index]->SetFrameSlot(output_offset, value);
858 return;
859 }
860 }
861}
862
863
864bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
865 int* input_offset) {
866 disasm::NameConverter converter;
867 FrameDescription* output = output_[0];
868
869 // The input values are all part of the unoptimized frame so they
870 // are all tagged pointers.
871 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
872 Object* input_object = reinterpret_cast<Object*>(input_value);
873
874 Translation::Opcode opcode =
875 static_cast<Translation::Opcode>(iterator->Next());
876 bool duplicate = (opcode == Translation::DUPLICATE);
877 if (duplicate) {
878 opcode = static_cast<Translation::Opcode>(iterator->Next());
879 }
880
881 switch (opcode) {
882 case Translation::BEGIN:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100883 case Translation::JS_FRAME:
884 case Translation::ARGUMENTS_ADAPTOR_FRAME:
885 case Translation::CONSTRUCT_STUB_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100886 case Translation::DUPLICATE:
887 UNREACHABLE(); // Malformed input.
888 return false;
889
890 case Translation::REGISTER: {
891 int output_reg = iterator->Next();
892 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100893 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100894 converter.NameOfCPURegister(output_reg),
895 input_value,
896 *input_offset);
897 }
898 output->SetRegister(output_reg, input_value);
899 break;
900 }
901
902 case Translation::INT32_REGISTER: {
903 // Abort OSR if we don't have a number.
904 if (!input_object->IsNumber()) return false;
905
906 int output_reg = iterator->Next();
907 int int32_value = input_object->IsSmi()
908 ? Smi::cast(input_object)->value()
909 : FastD2I(input_object->Number());
910 // Abort the translation if the conversion lost information.
911 if (!input_object->IsSmi() &&
912 FastI2D(int32_value) != input_object->Number()) {
913 if (FLAG_trace_osr) {
914 PrintF("**** %g could not be converted to int32 ****\n",
915 input_object->Number());
916 }
917 return false;
918 }
919 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100920 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100921 converter.NameOfCPURegister(output_reg),
922 int32_value,
923 *input_offset);
924 }
925 output->SetRegister(output_reg, int32_value);
926 break;
927 }
928
929 case Translation::DOUBLE_REGISTER: {
930 // Abort OSR if we don't have a number.
931 if (!input_object->IsNumber()) return false;
932
933 int output_reg = iterator->Next();
934 double double_value = input_object->Number();
935 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100936 PrintF(" %s <- %g (double) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100937 DoubleRegister::AllocationIndexToString(output_reg),
938 double_value,
939 *input_offset);
940 }
941 output->SetDoubleRegister(output_reg, double_value);
942 break;
943 }
944
945 case Translation::STACK_SLOT: {
946 int output_index = iterator->Next();
947 unsigned output_offset =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100948 output->GetOffsetFromSlotIndex(output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100949 if (FLAG_trace_osr) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100950 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100951 output_offset,
952 input_value,
953 *input_offset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100954 reinterpret_cast<Object*>(input_value)->ShortPrint();
955 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100956 }
957 output->SetFrameSlot(output_offset, input_value);
958 break;
959 }
960
961 case Translation::INT32_STACK_SLOT: {
962 // Abort OSR if we don't have a number.
963 if (!input_object->IsNumber()) return false;
964
965 int output_index = iterator->Next();
966 unsigned output_offset =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100967 output->GetOffsetFromSlotIndex(output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100968 int int32_value = input_object->IsSmi()
969 ? Smi::cast(input_object)->value()
970 : DoubleToInt32(input_object->Number());
971 // Abort the translation if the conversion lost information.
972 if (!input_object->IsSmi() &&
973 FastI2D(int32_value) != input_object->Number()) {
974 if (FLAG_trace_osr) {
975 PrintF("**** %g could not be converted to int32 ****\n",
976 input_object->Number());
977 }
978 return false;
979 }
980 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100981 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100982 output_offset,
983 int32_value,
984 *input_offset);
985 }
986 output->SetFrameSlot(output_offset, int32_value);
987 break;
988 }
989
990 case Translation::DOUBLE_STACK_SLOT: {
991 static const int kLowerOffset = 0 * kPointerSize;
992 static const int kUpperOffset = 1 * kPointerSize;
993
994 // Abort OSR if we don't have a number.
995 if (!input_object->IsNumber()) return false;
996
997 int output_index = iterator->Next();
998 unsigned output_offset =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100999 output->GetOffsetFromSlotIndex(output_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001000 double double_value = input_object->Number();
1001 uint64_t int_value = BitCast<uint64_t, double>(double_value);
1002 int32_t lower = static_cast<int32_t>(int_value);
1003 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
1004 if (FLAG_trace_osr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001005 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001006 output_offset + kUpperOffset,
1007 upper,
1008 double_value,
1009 *input_offset);
Steve Block1e0659c2011-05-24 12:43:12 +01001010 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001011 output_offset + kLowerOffset,
1012 lower,
1013 double_value,
1014 *input_offset);
1015 }
1016 output->SetFrameSlot(output_offset + kLowerOffset, lower);
1017 output->SetFrameSlot(output_offset + kUpperOffset, upper);
1018 break;
1019 }
1020
1021 case Translation::LITERAL: {
1022 // Just ignore non-materialized literals.
1023 iterator->Next();
1024 break;
1025 }
1026
1027 case Translation::ARGUMENTS_OBJECT: {
1028 // Optimized code assumes that the argument object has not been
1029 // materialized and so bypasses it when doing arguments access.
1030 // We should have bailed out before starting the frame
1031 // translation.
1032 UNREACHABLE();
1033 return false;
1034 }
1035 }
1036
1037 if (!duplicate) *input_offset -= kPointerSize;
1038 return true;
1039}
1040
1041
Steve Block1e0659c2011-05-24 12:43:12 +01001042void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
1043 Code* check_code,
1044 Code* replacement_code) {
1045 // Iterate over the stack check table and patch every stack check
1046 // call to an unconditional call to the replacement code.
1047 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1048 Address stack_check_cursor = unoptimized_code->instruction_start() +
1049 unoptimized_code->stack_check_table_offset();
1050 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1051 stack_check_cursor += kIntSize;
1052 for (uint32_t i = 0; i < table_length; ++i) {
1053 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1054 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001055 PatchStackCheckCodeAt(unoptimized_code,
1056 pc_after,
1057 check_code,
1058 replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +01001059 stack_check_cursor += 2 * kIntSize;
1060 }
1061}
1062
1063
1064void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
1065 Code* check_code,
1066 Code* replacement_code) {
1067 // Iterate over the stack check table and revert the patched
1068 // stack check calls.
1069 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1070 Address stack_check_cursor = unoptimized_code->instruction_start() +
1071 unoptimized_code->stack_check_table_offset();
1072 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1073 stack_check_cursor += kIntSize;
1074 for (uint32_t i = 0; i < table_length; ++i) {
1075 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1076 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001077 RevertStackCheckCodeAt(unoptimized_code,
1078 pc_after,
1079 check_code,
1080 replacement_code);
Steve Block1e0659c2011-05-24 12:43:12 +01001081 stack_check_cursor += 2 * kIntSize;
1082 }
1083}
1084
1085
Ben Murdochb0fe1622011-05-05 13:52:32 +01001086unsigned Deoptimizer::ComputeInputFrameSize() const {
1087 unsigned fixed_size = ComputeFixedSize(function_);
1088 // The fp-to-sp delta already takes the context and the function
1089 // into account so we have to avoid double counting them (-2).
1090 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
1091#ifdef DEBUG
1092 if (bailout_type_ == OSR) {
1093 // TODO(kasperl): It would be nice if we could verify that the
1094 // size matches with the stack height we can compute based on the
1095 // environment at the OSR entry. The code for that his built into
1096 // the DoComputeOsrOutputFrame function for now.
1097 } else {
1098 unsigned stack_slots = optimized_code_->stack_slots();
1099 unsigned outgoing_size = ComputeOutgoingArgumentSize();
1100 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
1101 }
1102#endif
1103 return result;
1104}
1105
1106
1107unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
1108 // The fixed part of the frame consists of the return address, frame
1109 // pointer, function, context, and all the incoming arguments.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001110 return ComputeIncomingArgumentSize(function) +
1111 StandardFrameConstants::kFixedFrameSize;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001112}
1113
1114
1115unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
1116 // The incoming arguments is the values for formal parameters and
1117 // the receiver. Every slot contains a pointer.
1118 unsigned arguments = function->shared()->formal_parameter_count() + 1;
1119 return arguments * kPointerSize;
1120}
1121
1122
1123unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
1124 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1125 optimized_code_->deoptimization_data());
1126 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
1127 return height * kPointerSize;
1128}
1129
1130
1131Object* Deoptimizer::ComputeLiteral(int index) const {
1132 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1133 optimized_code_->deoptimization_data());
1134 FixedArray* literals = data->LiteralArray();
1135 return literals->get(index);
1136}
1137
1138
Ben Murdoch8b112d22011-06-08 16:22:53 +01001139void Deoptimizer::AddDoubleValue(intptr_t slot_address,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001140 double value) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001141 HeapNumberMaterializationDescriptor value_desc(
1142 reinterpret_cast<Address>(slot_address), value);
1143 deferred_heap_numbers_.Add(value_desc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001144}
1145
1146
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001147MemoryChunk* Deoptimizer::CreateCode(BailoutType type) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001148 // We cannot run this if the serializer is enabled because this will
1149 // cause us to emit relocation information for the external
1150 // references. This is fine because the deoptimizer's code section
1151 // isn't meant to be serialized at all.
1152 ASSERT(!Serializer::enabled());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001153
Ben Murdoch8b112d22011-06-08 16:22:53 +01001154 MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
Steve Block44f0eee2011-05-26 01:26:41 +01001155 masm.set_emit_debug_code(false);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001156 GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
1157 CodeDesc desc;
1158 masm.GetCode(&desc);
1159 ASSERT(desc.reloc_size == 0);
1160
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001161 MemoryChunk* chunk =
1162 Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
1163 EXECUTABLE,
1164 NULL);
1165 ASSERT(chunk->area_size() >= desc.instr_size);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001166 if (chunk == NULL) {
1167 V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
1168 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001169 memcpy(chunk->area_start(), desc.buffer, desc.instr_size);
1170 CPU::FlushICache(chunk->area_start(), desc.instr_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001171 return chunk;
1172}
1173
1174
1175Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
Steve Block44f0eee2011-05-26 01:26:41 +01001176 DeoptimizingCodeListNode* node =
1177 Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001178 while (node != NULL) {
1179 if (node->code()->contains(addr)) return *node->code();
1180 node = node->next();
1181 }
1182 return NULL;
1183}
1184
1185
1186void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
Steve Block44f0eee2011-05-26 01:26:41 +01001187 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
1188 ASSERT(data->deoptimizing_code_list_ != NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001189 // Run through the code objects to find this one and remove it.
1190 DeoptimizingCodeListNode* prev = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01001191 DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001192 while (current != NULL) {
1193 if (*current->code() == code) {
1194 // Unlink from list. If prev is NULL we are looking at the first element.
1195 if (prev == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001196 data->deoptimizing_code_list_ = current->next();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001197 } else {
1198 prev->set_next(current->next());
1199 }
1200 delete current;
1201 return;
1202 }
1203 // Move to next in list.
1204 prev = current;
1205 current = current->next();
1206 }
1207 // Deoptimizing code is removed through weak callback. Each object is expected
1208 // to be removed once and only once.
1209 UNREACHABLE();
1210}
1211
1212
1213FrameDescription::FrameDescription(uint32_t frame_size,
1214 JSFunction* function)
1215 : frame_size_(frame_size),
1216 function_(function),
1217 top_(kZapUint32),
1218 pc_(kZapUint32),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001219 fp_(kZapUint32),
1220 context_(kZapUint32) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001221 // Zap all the registers.
1222 for (int r = 0; r < Register::kNumRegisters; r++) {
1223 SetRegister(r, kZapUint32);
1224 }
1225
1226 // Zap all the slots.
1227 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
1228 SetFrameSlot(o, kZapUint32);
1229 }
1230}
1231
1232
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001233int FrameDescription::ComputeFixedSize() {
1234 return StandardFrameConstants::kFixedFrameSize +
1235 (ComputeParametersCount() + 1) * kPointerSize;
1236}
1237
1238
1239unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001240 if (slot_index >= 0) {
1241 // Local or spill slots. Skip the fixed part of the frame
1242 // including all arguments.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001243 unsigned base = GetFrameSize() - ComputeFixedSize();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001244 return base - ((slot_index + 1) * kPointerSize);
1245 } else {
1246 // Incoming parameter.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001247 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
1248 unsigned base = GetFrameSize() - arg_size;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001249 return base - ((slot_index + 1) * kPointerSize);
1250 }
1251}
1252
1253
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001254int FrameDescription::ComputeParametersCount() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001255 switch (type_) {
1256 case StackFrame::JAVA_SCRIPT:
1257 return function_->shared()->formal_parameter_count();
1258 case StackFrame::ARGUMENTS_ADAPTOR: {
1259 // Last slot contains number of incomming arguments as a smi.
1260 // Can't use GetExpression(0) because it would cause infinite recursion.
1261 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value();
1262 }
1263 default:
1264 UNREACHABLE();
1265 return 0;
1266 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001267}
1268
1269
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001270Object* FrameDescription::GetParameter(int index) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001271 ASSERT(index >= 0);
1272 ASSERT(index < ComputeParametersCount());
1273 // The slot indexes for incoming arguments are negative.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001274 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001275 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1276}
1277
1278
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001279unsigned FrameDescription::GetExpressionCount() {
1280 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1281 unsigned size = GetFrameSize() - ComputeFixedSize();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001282 return size / kPointerSize;
1283}
1284
1285
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001286Object* FrameDescription::GetExpression(int index) {
1287 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1288 unsigned offset = GetOffsetFromSlotIndex(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001289 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1290}
1291
1292
Ben Murdochb0fe1622011-05-05 13:52:32 +01001293void TranslationBuffer::Add(int32_t value) {
1294 // Encode the sign bit in the least significant bit.
1295 bool is_negative = (value < 0);
1296 uint32_t bits = ((is_negative ? -value : value) << 1) |
1297 static_cast<int32_t>(is_negative);
1298 // Encode the individual bytes using the least significant bit of
1299 // each byte to indicate whether or not more bytes follow.
1300 do {
1301 uint32_t next = bits >> 7;
1302 contents_.Add(((bits << 1) & 0xFF) | (next != 0));
1303 bits = next;
1304 } while (bits != 0);
1305}
1306
1307
1308int32_t TranslationIterator::Next() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001309 // Run through the bytes until we reach one with a least significant
1310 // bit of zero (marks the end).
1311 uint32_t bits = 0;
1312 for (int i = 0; true; i += 7) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001313 ASSERT(HasNext());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001314 uint8_t next = buffer_->get(index_++);
1315 bits |= (next >> 1) << i;
1316 if ((next & 1) == 0) break;
1317 }
1318 // The bits encode the sign in the least significant bit.
1319 bool is_negative = (bits & 1) == 1;
1320 int32_t result = bits >> 1;
1321 return is_negative ? -result : result;
1322}
1323
1324
1325Handle<ByteArray> TranslationBuffer::CreateByteArray() {
1326 int length = contents_.length();
Steve Block44f0eee2011-05-26 01:26:41 +01001327 Handle<ByteArray> result =
1328 Isolate::Current()->factory()->NewByteArray(length, TENURED);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001329 memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
1330 return result;
1331}
1332
1333
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001334void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
1335 buffer_->Add(CONSTRUCT_STUB_FRAME);
1336 buffer_->Add(literal_id);
1337 buffer_->Add(height);
1338}
1339
1340
1341void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
1342 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME);
1343 buffer_->Add(literal_id);
1344 buffer_->Add(height);
1345}
1346
1347
1348void Translation::BeginJSFrame(int node_id, int literal_id, unsigned height) {
1349 buffer_->Add(JS_FRAME);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001350 buffer_->Add(node_id);
1351 buffer_->Add(literal_id);
1352 buffer_->Add(height);
1353}
1354
1355
1356void Translation::StoreRegister(Register reg) {
1357 buffer_->Add(REGISTER);
1358 buffer_->Add(reg.code());
1359}
1360
1361
1362void Translation::StoreInt32Register(Register reg) {
1363 buffer_->Add(INT32_REGISTER);
1364 buffer_->Add(reg.code());
1365}
1366
1367
1368void Translation::StoreDoubleRegister(DoubleRegister reg) {
1369 buffer_->Add(DOUBLE_REGISTER);
1370 buffer_->Add(DoubleRegister::ToAllocationIndex(reg));
1371}
1372
1373
1374void Translation::StoreStackSlot(int index) {
1375 buffer_->Add(STACK_SLOT);
1376 buffer_->Add(index);
1377}
1378
1379
1380void Translation::StoreInt32StackSlot(int index) {
1381 buffer_->Add(INT32_STACK_SLOT);
1382 buffer_->Add(index);
1383}
1384
1385
1386void Translation::StoreDoubleStackSlot(int index) {
1387 buffer_->Add(DOUBLE_STACK_SLOT);
1388 buffer_->Add(index);
1389}
1390
1391
1392void Translation::StoreLiteral(int literal_id) {
1393 buffer_->Add(LITERAL);
1394 buffer_->Add(literal_id);
1395}
1396
1397
1398void Translation::StoreArgumentsObject() {
1399 buffer_->Add(ARGUMENTS_OBJECT);
1400}
1401
1402
1403void Translation::MarkDuplicate() {
1404 buffer_->Add(DUPLICATE);
1405}
1406
1407
1408int Translation::NumberOfOperandsFor(Opcode opcode) {
1409 switch (opcode) {
1410 case ARGUMENTS_OBJECT:
1411 case DUPLICATE:
1412 return 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001413 case REGISTER:
1414 case INT32_REGISTER:
1415 case DOUBLE_REGISTER:
1416 case STACK_SLOT:
1417 case INT32_STACK_SLOT:
1418 case DOUBLE_STACK_SLOT:
1419 case LITERAL:
1420 return 1;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001421 case BEGIN:
1422 case ARGUMENTS_ADAPTOR_FRAME:
1423 case CONSTRUCT_STUB_FRAME:
1424 return 2;
1425 case JS_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +01001426 return 3;
1427 }
1428 UNREACHABLE();
1429 return -1;
1430}
1431
1432
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001433#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001434
1435const char* Translation::StringFor(Opcode opcode) {
1436 switch (opcode) {
1437 case BEGIN:
1438 return "BEGIN";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001439 case JS_FRAME:
1440 return "JS_FRAME";
1441 case ARGUMENTS_ADAPTOR_FRAME:
1442 return "ARGUMENTS_ADAPTOR_FRAME";
1443 case CONSTRUCT_STUB_FRAME:
1444 return "CONSTRUCT_STUB_FRAME";
Ben Murdochb0fe1622011-05-05 13:52:32 +01001445 case REGISTER:
1446 return "REGISTER";
1447 case INT32_REGISTER:
1448 return "INT32_REGISTER";
1449 case DOUBLE_REGISTER:
1450 return "DOUBLE_REGISTER";
1451 case STACK_SLOT:
1452 return "STACK_SLOT";
1453 case INT32_STACK_SLOT:
1454 return "INT32_STACK_SLOT";
1455 case DOUBLE_STACK_SLOT:
1456 return "DOUBLE_STACK_SLOT";
1457 case LITERAL:
1458 return "LITERAL";
1459 case ARGUMENTS_OBJECT:
1460 return "ARGUMENTS_OBJECT";
1461 case DUPLICATE:
1462 return "DUPLICATE";
1463 }
1464 UNREACHABLE();
1465 return "";
1466}
1467
1468#endif
1469
1470
1471DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001472 GlobalHandles* global_handles = Isolate::Current()->global_handles();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001473 // Globalize the code object and make it weak.
Steve Block44f0eee2011-05-26 01:26:41 +01001474 code_ = Handle<Code>::cast(global_handles->Create(code));
1475 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
1476 this,
1477 Deoptimizer::HandleWeakDeoptimizedCode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001478}
1479
1480
1481DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
Steve Block44f0eee2011-05-26 01:26:41 +01001482 GlobalHandles* global_handles = Isolate::Current()->global_handles();
1483 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001484}
1485
1486
Ben Murdoch8b112d22011-06-08 16:22:53 +01001487// We can't intermix stack decoding and allocations because
1488// deoptimization infrastracture is not GC safe.
1489// Thus we build a temporary structure in malloced space.
1490SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
1491 DeoptimizationInputData* data,
1492 JavaScriptFrame* frame) {
1493 Translation::Opcode opcode =
1494 static_cast<Translation::Opcode>(iterator->Next());
1495
1496 switch (opcode) {
1497 case Translation::BEGIN:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001498 case Translation::JS_FRAME:
1499 case Translation::ARGUMENTS_ADAPTOR_FRAME:
1500 case Translation::CONSTRUCT_STUB_FRAME:
Ben Murdoch8b112d22011-06-08 16:22:53 +01001501 // Peeled off before getting here.
1502 break;
1503
1504 case Translation::ARGUMENTS_OBJECT:
1505 // This can be only emitted for local slots not for argument slots.
1506 break;
1507
1508 case Translation::REGISTER:
1509 case Translation::INT32_REGISTER:
1510 case Translation::DOUBLE_REGISTER:
1511 case Translation::DUPLICATE:
1512 // We are at safepoint which corresponds to call. All registers are
1513 // saved by caller so there would be no live registers at this
1514 // point. Thus these translation commands should not be used.
1515 break;
1516
1517 case Translation::STACK_SLOT: {
1518 int slot_index = iterator->Next();
1519 Address slot_addr = SlotAddress(frame, slot_index);
1520 return SlotRef(slot_addr, SlotRef::TAGGED);
1521 }
1522
1523 case Translation::INT32_STACK_SLOT: {
1524 int slot_index = iterator->Next();
1525 Address slot_addr = SlotAddress(frame, slot_index);
1526 return SlotRef(slot_addr, SlotRef::INT32);
1527 }
1528
1529 case Translation::DOUBLE_STACK_SLOT: {
1530 int slot_index = iterator->Next();
1531 Address slot_addr = SlotAddress(frame, slot_index);
1532 return SlotRef(slot_addr, SlotRef::DOUBLE);
1533 }
1534
1535 case Translation::LITERAL: {
1536 int literal_index = iterator->Next();
1537 return SlotRef(data->LiteralArray()->get(literal_index));
1538 }
1539 }
1540
1541 UNREACHABLE();
1542 return SlotRef();
1543}
1544
1545
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001546void SlotRef::ComputeSlotsForArguments(Vector<SlotRef>* args_slots,
1547 TranslationIterator* it,
1548 DeoptimizationInputData* data,
1549 JavaScriptFrame* frame) {
1550 // Process the translation commands for the arguments.
1551
1552 // Skip the translation command for the receiver.
1553 it->Skip(Translation::NumberOfOperandsFor(
1554 static_cast<Translation::Opcode>(it->Next())));
1555
1556 // Compute slots for arguments.
1557 for (int i = 0; i < args_slots->length(); ++i) {
1558 (*args_slots)[i] = ComputeSlotForNextArgument(it, data, frame);
1559 }
1560}
1561
1562
1563Vector<SlotRef> SlotRef::ComputeSlotMappingForArguments(
1564 JavaScriptFrame* frame,
1565 int inlined_jsframe_index,
1566 int formal_parameter_count) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001567 AssertNoAllocation no_gc;
1568 int deopt_index = AstNode::kNoNumber;
1569 DeoptimizationInputData* data =
1570 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
1571 TranslationIterator it(data->TranslationByteArray(),
1572 data->TranslationIndex(deopt_index)->value());
1573 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1574 ASSERT(opcode == Translation::BEGIN);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001575 it.Next(); // Drop frame count.
1576 int jsframe_count = it.Next();
1577 USE(jsframe_count);
1578 ASSERT(jsframe_count > inlined_jsframe_index);
1579 int jsframes_to_skip = inlined_jsframe_index;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001580 while (true) {
1581 opcode = static_cast<Translation::Opcode>(it.Next());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001582 if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) {
1583 if (jsframes_to_skip == 0) {
1584 ASSERT(Translation::NumberOfOperandsFor(opcode) == 2);
1585
1586 it.Skip(1); // literal id
1587 int height = it.Next();
1588
1589 // We reached the arguments adaptor frame corresponding to the
1590 // inlined function in question. Number of arguments is height - 1.
1591 Vector<SlotRef> args_slots =
1592 Vector<SlotRef>::New(height - 1); // Minus receiver.
1593 ComputeSlotsForArguments(&args_slots, &it, data, frame);
1594 return args_slots;
1595 }
1596 } else if (opcode == Translation::JS_FRAME) {
1597 if (jsframes_to_skip == 0) {
1598 // Skip over operands to advance to the next opcode.
1599 it.Skip(Translation::NumberOfOperandsFor(opcode));
1600
Ben Murdoch85b71792012-04-11 18:30:58 +01001601 // We reached the frame corresponding to the inlined function
1602 // in question. Process the translation commands for the
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001603 // arguments. Number of arguments is equal to the number of
1604 // format parameter count.
1605 Vector<SlotRef> args_slots =
1606 Vector<SlotRef>::New(formal_parameter_count);
1607 ComputeSlotsForArguments(&args_slots, &it, data, frame);
1608 return args_slots;
Ben Murdoch85b71792012-04-11 18:30:58 +01001609 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001610 jsframes_to_skip--;
Ben Murdoch85b71792012-04-11 18:30:58 +01001611 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001612
1613 // Skip over operands to advance to the next opcode.
1614 it.Skip(Translation::NumberOfOperandsFor(opcode));
Ben Murdoch8b112d22011-06-08 16:22:53 +01001615 }
1616
1617 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001618 return Vector<SlotRef>();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001619}
1620
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001621#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch8b112d22011-06-08 16:22:53 +01001622
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001623DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
1624 int frame_index,
1625 bool has_arguments_adaptor,
1626 bool has_construct_stub) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001627 FrameDescription* output_frame = deoptimizer->output_[frame_index];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001628 function_ = output_frame->GetFunction();
1629 has_construct_stub_ = has_construct_stub;
1630 expression_count_ = output_frame->GetExpressionCount();
1631 expression_stack_ = new Object*[expression_count_];
1632 // Get the source position using the unoptimized code.
1633 Address pc = reinterpret_cast<Address>(output_frame->GetPc());
1634 Code* code = Code::cast(Isolate::Current()->heap()->FindCodeObject(pc));
1635 source_position_ = code->SourcePosition(pc);
1636
1637 for (int i = 0; i < expression_count_; i++) {
1638 SetExpression(i, output_frame->GetExpression(i));
1639 }
1640
1641 if (has_arguments_adaptor) {
1642 output_frame = deoptimizer->output_[frame_index - 1];
1643 ASSERT(output_frame->GetFrameType() == StackFrame::ARGUMENTS_ADAPTOR);
1644 }
1645
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001646 parameters_count_ = output_frame->ComputeParametersCount();
1647 parameters_ = new Object*[parameters_count_];
1648 for (int i = 0; i < parameters_count_; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001649 SetParameter(i, output_frame->GetParameter(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001650 }
1651}
1652
1653
1654DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
1655 delete[] expression_stack_;
1656 delete[] parameters_;
1657}
1658
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001659
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001660void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
1661 v->VisitPointer(BitCast<Object**>(&function_));
1662 v->VisitPointers(parameters_, parameters_ + parameters_count_);
1663 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
1664}
1665
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001666#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001667
Ben Murdochb0fe1622011-05-05 13:52:32 +01001668} } // namespace v8::internal