blob: f6eafd87589a891c56c5e15ddf41f3e9fcc98df9 [file] [log] [blame]
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// 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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042DeoptimizerData::DeoptimizerData() {
43 eager_deoptimization_entry_code_ = NULL;
44 lazy_deoptimization_entry_code_ = NULL;
45 current_ = NULL;
46 deoptimizing_code_list_ = NULL;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000047#ifdef ENABLE_DEBUGGER_SUPPORT
48 deoptimized_frame_info_ = NULL;
49#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000050}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051
52
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000053DeoptimizerData::~DeoptimizerData() {
54 if (eager_deoptimization_entry_code_ != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000055 Isolate::Current()->memory_allocator()->Free(
56 eager_deoptimization_entry_code_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000057 eager_deoptimization_entry_code_ = NULL;
58 }
59 if (lazy_deoptimization_entry_code_ != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000060 Isolate::Current()->memory_allocator()->Free(
61 lazy_deoptimization_entry_code_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000062 lazy_deoptimization_entry_code_ = NULL;
63 }
64}
65
ricow@chromium.org4f693d62011-07-04 14:01:31 +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
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +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.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000078Deoptimizer* Deoptimizer::New(JSFunction* function,
79 BailoutType type,
80 unsigned bailout_id,
81 Address from,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000082 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,
ricow@chromium.org4f693d62011-07-04 14:01:31 +000090 fp_to_sp_delta,
91 NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000092 ASSERT(isolate->deoptimizer_data()->current_ == NULL);
93 isolate->deoptimizer_data()->current_ = deoptimizer;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000094 return deoptimizer;
95}
96
97
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000098Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
99 ASSERT(isolate == Isolate::Current());
100 Deoptimizer* result = isolate->deoptimizer_data()->current_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000101 ASSERT(result != NULL);
102 result->DeleteFrameDescriptions();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000103 isolate->deoptimizer_data()->current_ = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000104 return result;
105}
106
yangguo@chromium.org659ceec2012-01-26 07:37:54 +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
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000124#ifdef ENABLE_DEBUGGER_SUPPORT
125DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
126 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000127 int jsframe_index,
ricow@chromium.org4f693d62011-07-04 14:01:31 +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();
ricow@chromium.org4f693d62011-07-04 14:01:31 +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.
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000139 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
140 int deoptimization_index = safepoint_entry.deoptimization_index();
ricow@chromium.org4f693d62011-07-04 14:01:31 +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.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +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
ulan@chromium.org967e2702012-02-28 09:49:15 +0000173 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);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000183 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
184
185 // Get the "simulated" top and size for the requested frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000186 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());
ricow@chromium.org4f693d62011-07-04 14:01:31 +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(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000204 parameters_top, parameters_size, expressions_top, expressions_size, info);
ricow@chromium.org4f693d62011-07-04 14:01:31 +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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000221
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) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000271 Isolate* isolate = context->GetIsolate();
272 ZoneScope zone_scope(isolate->runtime_zone(), DELETE_ON_EXIT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000273 AssertNoAllocation no_allocation;
274
275 ASSERT(context->IsGlobalContext());
276
277 visitor->EnterContext(context);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000278
279 // Create a snapshot of the optimized functions list. This is needed because
280 // visitors might remove more than one link from the list at once.
281 ZoneList<JSFunction*> snapshot(1, isolate->runtime_zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000282 Object* element = context->OptimizedFunctionsListHead();
283 while (!element->IsUndefined()) {
284 JSFunction* element_function = JSFunction::cast(element);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000285 snapshot.Add(element_function, isolate->runtime_zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000286 element = element_function->next_function_link();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000287 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000288
289 // Run through the snapshot of optimized functions and visit them.
290 for (int i = 0; i < snapshot.length(); ++i) {
291 visitor->VisitFunction(snapshot.at(i));
292 }
293
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294 visitor->LeaveContext(context);
295}
296
297
298void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
299 JSObject* object, OptimizedFunctionVisitor* visitor) {
300 AssertNoAllocation no_allocation;
301
302 if (object->IsJSGlobalProxy()) {
303 Object* proto = object->GetPrototype();
304 ASSERT(proto->IsJSGlobalObject());
305 VisitAllOptimizedFunctionsForContext(
306 GlobalObject::cast(proto)->global_context(), visitor);
307 } else if (object->IsGlobalObject()) {
308 VisitAllOptimizedFunctionsForContext(
309 GlobalObject::cast(object)->global_context(), visitor);
310 }
311}
312
313
314void Deoptimizer::VisitAllOptimizedFunctions(
315 OptimizedFunctionVisitor* visitor) {
316 AssertNoAllocation no_allocation;
317
318 // Run through the list of all global contexts and deoptimize.
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000319 Object* context = Isolate::Current()->heap()->global_contexts_list();
320 while (!context->IsUndefined()) {
321 // GC can happen when the context is not fully initialized,
322 // so the global field of the context can be undefined.
323 Object* global = Context::cast(context)->get(Context::GLOBAL_INDEX);
324 if (!global->IsUndefined()) {
325 VisitAllOptimizedFunctionsForGlobalObject(JSObject::cast(global),
326 visitor);
327 }
328 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000329 }
330}
331
332
333void Deoptimizer::HandleWeakDeoptimizedCode(
334 v8::Persistent<v8::Value> obj, void* data) {
335 DeoptimizingCodeListNode* node =
336 reinterpret_cast<DeoptimizingCodeListNode*>(data);
337 RemoveDeoptimizingCode(*node->code());
338#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000340 while (node != NULL) {
341 ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
342 node = node->next();
343 }
344#endif
345}
346
347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000348void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000349 deoptimizer->DoComputeOutputFrames();
350}
351
352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000353Deoptimizer::Deoptimizer(Isolate* isolate,
354 JSFunction* function,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000355 BailoutType type,
356 unsigned bailout_id,
357 Address from,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000358 int fp_to_sp_delta,
359 Code* optimized_code)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 : isolate_(isolate),
361 function_(function),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000362 bailout_id_(bailout_id),
363 bailout_type_(type),
364 from_(from),
365 fp_to_sp_delta_(fp_to_sp_delta),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000366 has_alignment_padding_(0),
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000367 input_(NULL),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000368 output_count_(0),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000369 jsframe_count_(0),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000370 output_(NULL),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000371 deferred_heap_numbers_(0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000372 if (FLAG_trace_deopt && type != OSR) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000373 if (type == DEBUGGER) {
374 PrintF("**** DEOPT FOR DEBUGGER: ");
375 } else {
376 PrintF("**** DEOPT: ");
377 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000378 function->PrintName();
379 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
380 bailout_id,
381 reinterpret_cast<intptr_t>(from),
382 fp_to_sp_delta - (2 * kPointerSize));
383 } else if (FLAG_trace_osr && type == OSR) {
384 PrintF("**** OSR: ");
385 function->PrintName();
386 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
387 bailout_id,
388 reinterpret_cast<intptr_t>(from),
389 fp_to_sp_delta - (2 * kPointerSize));
390 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000391 function->shared()->increment_deopt_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000392 // Find the optimized code.
393 if (type == EAGER) {
394 ASSERT(from == NULL);
395 optimized_code_ = function_->code();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000396 if (FLAG_trace_deopt && FLAG_code_comments) {
397 // Print instruction associated with this bailout.
398 const char* last_comment = NULL;
399 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
400 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
401 for (RelocIterator it(optimized_code_, mask); !it.done(); it.next()) {
402 RelocInfo* info = it.rinfo();
403 if (info->rmode() == RelocInfo::COMMENT) {
404 last_comment = reinterpret_cast<const char*>(info->data());
405 }
406 if (info->rmode() == RelocInfo::RUNTIME_ENTRY) {
407 unsigned id = Deoptimizer::GetDeoptimizationId(
408 info->target_address(), Deoptimizer::EAGER);
409 if (id == bailout_id && last_comment != NULL) {
410 PrintF(" %s\n", last_comment);
411 break;
412 }
413 }
414 }
415 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000416 } else if (type == LAZY) {
417 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
418 ASSERT(optimized_code_ != NULL);
419 } else if (type == OSR) {
420 // The function has already been optimized and we're transitioning
421 // from the unoptimized shared version to the optimized one in the
422 // function. The return address (from) points to unoptimized code.
423 optimized_code_ = function_->code();
424 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
425 ASSERT(!optimized_code_->contains(from));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000426 } else if (type == DEBUGGER) {
427 optimized_code_ = optimized_code;
428 ASSERT(optimized_code_->contains(from));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000429 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 ASSERT(HEAP->allow_allocation(false));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000431 unsigned size = ComputeInputFrameSize();
432 input_ = new(size) FrameDescription(size, function);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000433 input_->SetFrameType(StackFrame::JAVA_SCRIPT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000434}
435
436
437Deoptimizer::~Deoptimizer() {
438 ASSERT(input_ == NULL && output_ == NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000439}
440
441
442void Deoptimizer::DeleteFrameDescriptions() {
443 delete input_;
444 for (int i = 0; i < output_count_; ++i) {
445 if (output_[i] != input_) delete output_[i];
446 }
447 delete[] output_;
448 input_ = NULL;
449 output_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 ASSERT(!HEAP->allow_allocation(true));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451}
452
453
454Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
455 ASSERT(id >= 0);
456 if (id >= kNumberOfEntries) return NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 MemoryChunk* base = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000459 if (type == EAGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 if (data->eager_deoptimization_entry_code_ == NULL) {
461 data->eager_deoptimization_entry_code_ = CreateCode(type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000462 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 base = data->eager_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000464 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000465 if (data->lazy_deoptimization_entry_code_ == NULL) {
466 data->lazy_deoptimization_entry_code_ = CreateCode(type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000467 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 base = data->lazy_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000469 }
470 return
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000471 static_cast<Address>(base->area_start()) + (id * table_entry_size_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000472}
473
474
475int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000476 MemoryChunk* base = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000477 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000478 if (type == EAGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000479 base = data->eager_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000480 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 base = data->lazy_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000482 }
483 if (base == NULL ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000484 addr < base->area_start() ||
485 addr >= base->area_start() +
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000486 (kNumberOfEntries * table_entry_size_)) {
487 return kNotDeoptimizationEntry;
488 }
489 ASSERT_EQ(0,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000490 static_cast<int>(addr - base->area_start()) % table_entry_size_);
491 return static_cast<int>(addr - base->area_start()) / table_entry_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000492}
493
494
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000495int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
496 unsigned id,
497 SharedFunctionInfo* shared) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000498 // TODO(kasperl): For now, we do a simple linear search for the PC
499 // offset associated with the given node id. This should probably be
500 // changed to a binary search.
501 int length = data->DeoptPoints();
502 Smi* smi_id = Smi::FromInt(id);
503 for (int i = 0; i < length; i++) {
504 if (data->AstId(i) == smi_id) {
505 return data->PcAndState(i)->value();
506 }
507 }
508 PrintF("[couldn't find pc offset for node=%u]\n", id);
509 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
510 // Print the source code if available.
511 HeapStringAllocator string_allocator;
512 StringStream stream(&string_allocator);
513 shared->SourceCodePrint(&stream, -1);
514 PrintF("[source:\n%s\n]", *stream.ToCString());
515
516 UNREACHABLE();
517 return -1;
518}
519
520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000522 int length = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 DeoptimizingCodeListNode* node =
524 isolate->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000525 while (node != NULL) {
526 length++;
527 node = node->next();
528 }
529 return length;
530}
531
532
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000533// We rely on this function not causing a GC. It is called from generated code
534// without having a real stack frame in place.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000535void Deoptimizer::DoComputeOutputFrames() {
536 if (bailout_type_ == OSR) {
537 DoComputeOsrOutputFrame();
538 return;
539 }
540
541 // Print some helpful diagnostic information.
542 int64_t start = OS::Ticks();
543 if (FLAG_trace_deopt) {
544 PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
545 (bailout_type_ == LAZY ? " (lazy)" : ""),
546 reinterpret_cast<intptr_t>(function_));
547 function_->PrintName();
548 PrintF(" @%d]\n", bailout_id_);
549 }
550
551 // Determine basic deoptimization information. The optimized frame is
552 // described by the input data.
553 DeoptimizationInputData* input_data =
554 DeoptimizationInputData::cast(optimized_code_->deoptimization_data());
555 unsigned node_id = input_data->AstId(bailout_id_)->value();
556 ByteArray* translations = input_data->TranslationByteArray();
557 unsigned translation_index =
558 input_data->TranslationIndex(bailout_id_)->value();
559
560 // Do the input frame to output frame(s) translation.
561 TranslationIterator iterator(translations, translation_index);
562 Translation::Opcode opcode =
563 static_cast<Translation::Opcode>(iterator.Next());
564 ASSERT(Translation::BEGIN == opcode);
565 USE(opcode);
566 // Read the number of output frames and allocate an array for their
567 // descriptions.
568 int count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000569 iterator.Next(); // Drop JS frames count.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000570 ASSERT(output_ == NULL);
571 output_ = new FrameDescription*[count];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000572 for (int i = 0; i < count; ++i) {
573 output_[i] = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000574 }
575 output_count_ = count;
576
577 // Translate each output frame.
578 for (int i = 0; i < count; ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000579 // Read the ast node id, function, and frame height for this output frame.
580 Translation::Opcode opcode =
581 static_cast<Translation::Opcode>(iterator.Next());
582 switch (opcode) {
583 case Translation::JS_FRAME:
584 DoComputeJSFrame(&iterator, i);
585 jsframe_count_++;
586 break;
587 case Translation::ARGUMENTS_ADAPTOR_FRAME:
588 DoComputeArgumentsAdaptorFrame(&iterator, i);
589 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000590 case Translation::CONSTRUCT_STUB_FRAME:
591 DoComputeConstructStubFrame(&iterator, i);
592 break;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000593 default:
594 UNREACHABLE();
595 break;
596 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000597 }
598
599 // Print some helpful diagnostic information.
600 if (FLAG_trace_deopt) {
601 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
602 int index = output_count_ - 1; // Index of the topmost frame.
603 JSFunction* function = output_[index]->GetFunction();
604 PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
605 reinterpret_cast<intptr_t>(function));
606 function->PrintName();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000607 PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
608 " took %0.3f ms]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000609 node_id,
610 output_[index]->GetPc(),
611 FullCodeGenerator::State2String(
612 static_cast<FullCodeGenerator::State>(
613 output_[index]->GetState()->value())),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000614 has_alignment_padding_ ? "with padding" : "no padding",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000615 ms);
616 }
617}
618
619
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000620void Deoptimizer::MaterializeHeapNumbers() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000621 ASSERT_NE(DEBUGGER, bailout_type_);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000622 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
623 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
624 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
625 if (FLAG_trace_deopt) {
626 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
627 reinterpret_cast<void*>(*num),
628 d.value(),
629 d.slot_address());
630 }
631
632 Memory::Object_at(d.slot_address()) = *num;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000633 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000634}
635
636
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000637#ifdef ENABLE_DEBUGGER_SUPPORT
638void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000639 Address parameters_top,
640 uint32_t parameters_size,
641 Address expressions_top,
642 uint32_t expressions_size,
643 DeoptimizedFrameInfo* info) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000644 ASSERT_EQ(DEBUGGER, bailout_type_);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000645 Address parameters_bottom = parameters_top + parameters_size;
646 Address expressions_bottom = expressions_top + expressions_size;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000647 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
648 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
649
650 // Check of the heap number to materialize actually belong to the frame
651 // being extracted.
652 Address slot = d.slot_address();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000653 if (parameters_top <= slot && slot < parameters_bottom) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000654 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000655
656 int index = (info->parameters_count() - 1) -
657 static_cast<int>(slot - parameters_top) / kPointerSize;
658
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000659 if (FLAG_trace_deopt) {
660 PrintF("Materializing a new heap number %p [%e] in slot %p"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000661 "for parameter slot #%d\n",
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000662 reinterpret_cast<void*>(*num),
663 d.value(),
664 d.slot_address(),
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000665 index);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000666 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000667
668 info->SetParameter(index, *num);
669 } else if (expressions_top <= slot && slot < expressions_bottom) {
670 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
671
672 int index = info->expression_count() - 1 -
673 static_cast<int>(slot - expressions_top) / kPointerSize;
674
675 if (FLAG_trace_deopt) {
676 PrintF("Materializing a new heap number %p [%e] in slot %p"
677 "for expression slot #%d\n",
678 reinterpret_cast<void*>(*num),
679 d.value(),
680 d.slot_address(),
681 index);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000682 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000683
684 info->SetExpression(index, *num);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000685 }
686 }
687}
688#endif
689
690
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000691void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
692 int frame_index,
693 unsigned output_offset) {
694 disasm::NameConverter converter;
695 // A GC-safe temporary placeholder that we can put in the output frame.
696 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
697
698 // Ignore commands marked as duplicate and act on the first non-duplicate.
699 Translation::Opcode opcode =
700 static_cast<Translation::Opcode>(iterator->Next());
701 while (opcode == Translation::DUPLICATE) {
702 opcode = static_cast<Translation::Opcode>(iterator->Next());
703 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
704 opcode = static_cast<Translation::Opcode>(iterator->Next());
705 }
706
707 switch (opcode) {
708 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000709 case Translation::JS_FRAME:
710 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +0000711 case Translation::CONSTRUCT_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000712 case Translation::DUPLICATE:
713 UNREACHABLE();
714 return;
715
716 case Translation::REGISTER: {
717 int input_reg = iterator->Next();
718 intptr_t input_value = input_->GetRegister(input_reg);
719 if (FLAG_trace_deopt) {
720 PrintF(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000721 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000722 output_[frame_index]->GetTop() + output_offset,
723 output_offset,
724 input_value,
725 converter.NameOfCPURegister(input_reg));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000726 reinterpret_cast<Object*>(input_value)->ShortPrint();
727 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000728 }
729 output_[frame_index]->SetFrameSlot(output_offset, input_value);
730 return;
731 }
732
733 case Translation::INT32_REGISTER: {
734 int input_reg = iterator->Next();
735 intptr_t value = input_->GetRegister(input_reg);
736 bool is_smi = Smi::IsValid(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000737 if (FLAG_trace_deopt) {
738 PrintF(
739 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
740 output_[frame_index]->GetTop() + output_offset,
741 output_offset,
742 value,
743 converter.NameOfCPURegister(input_reg),
744 is_smi ? "smi" : "heap number");
745 }
746 if (is_smi) {
747 intptr_t tagged_value =
748 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
749 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
750 } else {
751 // We save the untagged value on the side and store a GC-safe
752 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000753 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
754 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000755 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
756 }
757 return;
758 }
759
760 case Translation::DOUBLE_REGISTER: {
761 int input_reg = iterator->Next();
762 double value = input_->GetDoubleRegister(input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000763 if (FLAG_trace_deopt) {
764 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
765 output_[frame_index]->GetTop() + output_offset,
766 output_offset,
767 value,
768 DoubleRegister::AllocationIndexToString(input_reg));
769 }
770 // We save the untagged value on the side and store a GC-safe
771 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000772 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000773 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
774 return;
775 }
776
777 case Translation::STACK_SLOT: {
778 int input_slot_index = iterator->Next();
779 unsigned input_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000780 input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000781 intptr_t input_value = input_->GetFrameSlot(input_offset);
782 if (FLAG_trace_deopt) {
783 PrintF(" 0x%08" V8PRIxPTR ": ",
784 output_[frame_index]->GetTop() + output_offset);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000785 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000786 output_offset,
787 input_value,
788 input_offset);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000789 reinterpret_cast<Object*>(input_value)->ShortPrint();
790 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000791 }
792 output_[frame_index]->SetFrameSlot(output_offset, input_value);
793 return;
794 }
795
796 case Translation::INT32_STACK_SLOT: {
797 int input_slot_index = iterator->Next();
798 unsigned input_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000799 input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000800 intptr_t value = input_->GetFrameSlot(input_offset);
801 bool is_smi = Smi::IsValid(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000802 if (FLAG_trace_deopt) {
803 PrintF(" 0x%08" V8PRIxPTR ": ",
804 output_[frame_index]->GetTop() + output_offset);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000805 PrintF("[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000806 output_offset,
807 value,
808 input_offset,
809 is_smi ? "smi" : "heap number");
810 }
811 if (is_smi) {
812 intptr_t tagged_value =
813 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
814 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
815 } else {
816 // We save the untagged value on the side and store a GC-safe
817 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000818 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
819 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000820 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
821 }
822 return;
823 }
824
825 case Translation::DOUBLE_STACK_SLOT: {
826 int input_slot_index = iterator->Next();
827 unsigned input_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000828 input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000829 double value = input_->GetDoubleFrameSlot(input_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000830 if (FLAG_trace_deopt) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000831 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000832 output_[frame_index]->GetTop() + output_offset,
833 output_offset,
834 value,
835 input_offset);
836 }
837 // We save the untagged value on the side and store a GC-safe
838 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000839 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000840 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
841 return;
842 }
843
844 case Translation::LITERAL: {
845 Object* literal = ComputeLiteral(iterator->Next());
846 if (FLAG_trace_deopt) {
847 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
848 output_[frame_index]->GetTop() + output_offset,
849 output_offset);
850 literal->ShortPrint();
851 PrintF(" ; literal\n");
852 }
853 intptr_t value = reinterpret_cast<intptr_t>(literal);
854 output_[frame_index]->SetFrameSlot(output_offset, value);
855 return;
856 }
857
858 case Translation::ARGUMENTS_OBJECT: {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000859 // Use the arguments marker value as a sentinel and fill in the arguments
860 // object after the deoptimized frame is built.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000861 if (FLAG_trace_deopt) {
862 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
863 output_[frame_index]->GetTop() + output_offset,
864 output_offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 isolate_->heap()->arguments_marker()->ShortPrint();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000866 PrintF(" ; arguments object\n");
867 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 intptr_t value = reinterpret_cast<intptr_t>(
869 isolate_->heap()->arguments_marker());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000870 output_[frame_index]->SetFrameSlot(output_offset, value);
871 return;
872 }
873 }
874}
875
876
877bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
878 int* input_offset) {
879 disasm::NameConverter converter;
880 FrameDescription* output = output_[0];
881
882 // The input values are all part of the unoptimized frame so they
883 // are all tagged pointers.
884 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
885 Object* input_object = reinterpret_cast<Object*>(input_value);
886
887 Translation::Opcode opcode =
888 static_cast<Translation::Opcode>(iterator->Next());
889 bool duplicate = (opcode == Translation::DUPLICATE);
890 if (duplicate) {
891 opcode = static_cast<Translation::Opcode>(iterator->Next());
892 }
893
894 switch (opcode) {
895 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000896 case Translation::JS_FRAME:
897 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +0000898 case Translation::CONSTRUCT_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000899 case Translation::DUPLICATE:
900 UNREACHABLE(); // Malformed input.
901 return false;
902
903 case Translation::REGISTER: {
904 int output_reg = iterator->Next();
905 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000906 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000907 converter.NameOfCPURegister(output_reg),
908 input_value,
909 *input_offset);
910 }
911 output->SetRegister(output_reg, input_value);
912 break;
913 }
914
915 case Translation::INT32_REGISTER: {
916 // Abort OSR if we don't have a number.
917 if (!input_object->IsNumber()) return false;
918
919 int output_reg = iterator->Next();
920 int int32_value = input_object->IsSmi()
921 ? Smi::cast(input_object)->value()
922 : FastD2I(input_object->Number());
923 // Abort the translation if the conversion lost information.
924 if (!input_object->IsSmi() &&
925 FastI2D(int32_value) != input_object->Number()) {
926 if (FLAG_trace_osr) {
927 PrintF("**** %g could not be converted to int32 ****\n",
928 input_object->Number());
929 }
930 return false;
931 }
932 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000933 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000934 converter.NameOfCPURegister(output_reg),
935 int32_value,
936 *input_offset);
937 }
938 output->SetRegister(output_reg, int32_value);
939 break;
940 }
941
942 case Translation::DOUBLE_REGISTER: {
943 // Abort OSR if we don't have a number.
944 if (!input_object->IsNumber()) return false;
945
946 int output_reg = iterator->Next();
947 double double_value = input_object->Number();
948 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000949 PrintF(" %s <- %g (double) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950 DoubleRegister::AllocationIndexToString(output_reg),
951 double_value,
952 *input_offset);
953 }
954 output->SetDoubleRegister(output_reg, double_value);
955 break;
956 }
957
958 case Translation::STACK_SLOT: {
959 int output_index = iterator->Next();
960 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000961 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000962 if (FLAG_trace_osr) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000963 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000964 output_offset,
965 input_value,
966 *input_offset);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000967 reinterpret_cast<Object*>(input_value)->ShortPrint();
968 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000969 }
970 output->SetFrameSlot(output_offset, input_value);
971 break;
972 }
973
974 case Translation::INT32_STACK_SLOT: {
975 // Abort OSR if we don't have a number.
976 if (!input_object->IsNumber()) return false;
977
978 int output_index = iterator->Next();
979 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000980 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000981 int int32_value = input_object->IsSmi()
982 ? Smi::cast(input_object)->value()
983 : DoubleToInt32(input_object->Number());
984 // Abort the translation if the conversion lost information.
985 if (!input_object->IsSmi() &&
986 FastI2D(int32_value) != input_object->Number()) {
987 if (FLAG_trace_osr) {
988 PrintF("**** %g could not be converted to int32 ****\n",
989 input_object->Number());
990 }
991 return false;
992 }
993 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000994 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000995 output_offset,
996 int32_value,
997 *input_offset);
998 }
999 output->SetFrameSlot(output_offset, int32_value);
1000 break;
1001 }
1002
1003 case Translation::DOUBLE_STACK_SLOT: {
1004 static const int kLowerOffset = 0 * kPointerSize;
1005 static const int kUpperOffset = 1 * kPointerSize;
1006
1007 // Abort OSR if we don't have a number.
1008 if (!input_object->IsNumber()) return false;
1009
1010 int output_index = iterator->Next();
1011 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001012 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001013 double double_value = input_object->Number();
1014 uint64_t int_value = BitCast<uint64_t, double>(double_value);
1015 int32_t lower = static_cast<int32_t>(int_value);
1016 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
1017 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001018 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 output_offset + kUpperOffset,
1020 upper,
1021 double_value,
1022 *input_offset);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001023 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001024 output_offset + kLowerOffset,
1025 lower,
1026 double_value,
1027 *input_offset);
1028 }
1029 output->SetFrameSlot(output_offset + kLowerOffset, lower);
1030 output->SetFrameSlot(output_offset + kUpperOffset, upper);
1031 break;
1032 }
1033
1034 case Translation::LITERAL: {
1035 // Just ignore non-materialized literals.
1036 iterator->Next();
1037 break;
1038 }
1039
1040 case Translation::ARGUMENTS_OBJECT: {
1041 // Optimized code assumes that the argument object has not been
1042 // materialized and so bypasses it when doing arguments access.
1043 // We should have bailed out before starting the frame
1044 // translation.
1045 UNREACHABLE();
1046 return false;
1047 }
1048 }
1049
1050 if (!duplicate) *input_offset -= kPointerSize;
1051 return true;
1052}
1053
1054
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001055void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
1056 Code* check_code,
1057 Code* replacement_code) {
1058 // Iterate over the stack check table and patch every stack check
1059 // call to an unconditional call to the replacement code.
1060 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1061 Address stack_check_cursor = unoptimized_code->instruction_start() +
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001062 unoptimized_code->stack_check_table_offset();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001063 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1064 stack_check_cursor += kIntSize;
1065 for (uint32_t i = 0; i < table_length; ++i) {
1066 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1067 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001068 PatchStackCheckCodeAt(unoptimized_code,
1069 pc_after,
1070 check_code,
1071 replacement_code);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001072 stack_check_cursor += 2 * kIntSize;
1073 }
1074}
1075
1076
1077void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
1078 Code* check_code,
1079 Code* replacement_code) {
1080 // Iterate over the stack check table and revert the patched
1081 // stack check calls.
1082 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1083 Address stack_check_cursor = unoptimized_code->instruction_start() +
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001084 unoptimized_code->stack_check_table_offset();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001085 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1086 stack_check_cursor += kIntSize;
1087 for (uint32_t i = 0; i < table_length; ++i) {
1088 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1089 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001090 RevertStackCheckCodeAt(unoptimized_code,
1091 pc_after,
1092 check_code,
1093 replacement_code);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001094 stack_check_cursor += 2 * kIntSize;
1095 }
1096}
1097
1098
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001099unsigned Deoptimizer::ComputeInputFrameSize() const {
1100 unsigned fixed_size = ComputeFixedSize(function_);
1101 // The fp-to-sp delta already takes the context and the function
1102 // into account so we have to avoid double counting them (-2).
1103 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
1104#ifdef DEBUG
1105 if (bailout_type_ == OSR) {
1106 // TODO(kasperl): It would be nice if we could verify that the
1107 // size matches with the stack height we can compute based on the
1108 // environment at the OSR entry. The code for that his built into
1109 // the DoComputeOsrOutputFrame function for now.
1110 } else {
1111 unsigned stack_slots = optimized_code_->stack_slots();
1112 unsigned outgoing_size = ComputeOutgoingArgumentSize();
1113 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
1114 }
1115#endif
1116 return result;
1117}
1118
1119
1120unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
1121 // The fixed part of the frame consists of the return address, frame
1122 // pointer, function, context, and all the incoming arguments.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001123 return ComputeIncomingArgumentSize(function) +
1124 StandardFrameConstants::kFixedFrameSize;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001125}
1126
1127
1128unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
1129 // The incoming arguments is the values for formal parameters and
1130 // the receiver. Every slot contains a pointer.
1131 unsigned arguments = function->shared()->formal_parameter_count() + 1;
1132 return arguments * kPointerSize;
1133}
1134
1135
1136unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
1137 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1138 optimized_code_->deoptimization_data());
1139 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
1140 return height * kPointerSize;
1141}
1142
1143
1144Object* Deoptimizer::ComputeLiteral(int index) const {
1145 DeoptimizationInputData* data = DeoptimizationInputData::cast(
1146 optimized_code_->deoptimization_data());
1147 FixedArray* literals = data->LiteralArray();
1148 return literals->get(index);
1149}
1150
1151
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001152void Deoptimizer::AddDoubleValue(intptr_t slot_address,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001153 double value) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001154 HeapNumberMaterializationDescriptor value_desc(
1155 reinterpret_cast<Address>(slot_address), value);
1156 deferred_heap_numbers_.Add(value_desc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001157}
1158
1159
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001160MemoryChunk* Deoptimizer::CreateCode(BailoutType type) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001161 // We cannot run this if the serializer is enabled because this will
1162 // cause us to emit relocation information for the external
1163 // references. This is fine because the deoptimizer's code section
1164 // isn't meant to be serialized at all.
1165 ASSERT(!Serializer::enabled());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001167 MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001168 masm.set_emit_debug_code(false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001169 GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
1170 CodeDesc desc;
1171 masm.GetCode(&desc);
1172 ASSERT(desc.reloc_size == 0);
1173
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001174 MemoryChunk* chunk =
1175 Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
1176 EXECUTABLE,
1177 NULL);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001178 ASSERT(chunk->area_size() >= desc.instr_size);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001179 if (chunk == NULL) {
1180 V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
1181 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001182 memcpy(chunk->area_start(), desc.buffer, desc.instr_size);
1183 CPU::FlushICache(chunk->area_start(), desc.instr_size);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001184 return chunk;
1185}
1186
1187
1188Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 DeoptimizingCodeListNode* node =
1190 Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001191 while (node != NULL) {
1192 if (node->code()->contains(addr)) return *node->code();
1193 node = node->next();
1194 }
1195 return NULL;
1196}
1197
1198
1199void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
1201 ASSERT(data->deoptimizing_code_list_ != NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001202 // Run through the code objects to find this one and remove it.
1203 DeoptimizingCodeListNode* prev = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001205 while (current != NULL) {
1206 if (*current->code() == code) {
1207 // Unlink from list. If prev is NULL we are looking at the first element.
1208 if (prev == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 data->deoptimizing_code_list_ = current->next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001210 } else {
1211 prev->set_next(current->next());
1212 }
1213 delete current;
1214 return;
1215 }
1216 // Move to next in list.
1217 prev = current;
1218 current = current->next();
1219 }
1220 // Deoptimizing code is removed through weak callback. Each object is expected
1221 // to be removed once and only once.
1222 UNREACHABLE();
1223}
1224
1225
1226FrameDescription::FrameDescription(uint32_t frame_size,
1227 JSFunction* function)
1228 : frame_size_(frame_size),
1229 function_(function),
1230 top_(kZapUint32),
1231 pc_(kZapUint32),
ulan@chromium.org967e2702012-02-28 09:49:15 +00001232 fp_(kZapUint32),
1233 context_(kZapUint32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001234 // Zap all the registers.
1235 for (int r = 0; r < Register::kNumRegisters; r++) {
1236 SetRegister(r, kZapUint32);
1237 }
1238
1239 // Zap all the slots.
1240 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
1241 SetFrameSlot(o, kZapUint32);
1242 }
1243}
1244
1245
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001246int FrameDescription::ComputeFixedSize() {
1247 return StandardFrameConstants::kFixedFrameSize +
1248 (ComputeParametersCount() + 1) * kPointerSize;
1249}
1250
1251
1252unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001253 if (slot_index >= 0) {
1254 // Local or spill slots. Skip the fixed part of the frame
1255 // including all arguments.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001256 unsigned base = GetFrameSize() - ComputeFixedSize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001257 return base - ((slot_index + 1) * kPointerSize);
1258 } else {
1259 // Incoming parameter.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001260 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
1261 unsigned base = GetFrameSize() - arg_size;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001262 return base - ((slot_index + 1) * kPointerSize);
1263 }
1264}
1265
1266
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001267int FrameDescription::ComputeParametersCount() {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001268 switch (type_) {
1269 case StackFrame::JAVA_SCRIPT:
1270 return function_->shared()->formal_parameter_count();
1271 case StackFrame::ARGUMENTS_ADAPTOR: {
1272 // Last slot contains number of incomming arguments as a smi.
1273 // Can't use GetExpression(0) because it would cause infinite recursion.
1274 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value();
1275 }
1276 default:
1277 UNREACHABLE();
1278 return 0;
1279 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001280}
1281
1282
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001283Object* FrameDescription::GetParameter(int index) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001284 ASSERT(index >= 0);
1285 ASSERT(index < ComputeParametersCount());
1286 // The slot indexes for incoming arguments are negative.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001287 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001288 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1289}
1290
1291
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001292unsigned FrameDescription::GetExpressionCount() {
1293 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1294 unsigned size = GetFrameSize() - ComputeFixedSize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001295 return size / kPointerSize;
1296}
1297
1298
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001299Object* FrameDescription::GetExpression(int index) {
1300 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1301 unsigned offset = GetOffsetFromSlotIndex(index);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001302 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1303}
1304
1305
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001306void TranslationBuffer::Add(int32_t value, Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001307 // Encode the sign bit in the least significant bit.
1308 bool is_negative = (value < 0);
1309 uint32_t bits = ((is_negative ? -value : value) << 1) |
1310 static_cast<int32_t>(is_negative);
1311 // Encode the individual bytes using the least significant bit of
1312 // each byte to indicate whether or not more bytes follow.
1313 do {
1314 uint32_t next = bits >> 7;
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001315 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001316 bits = next;
1317 } while (bits != 0);
1318}
1319
1320
1321int32_t TranslationIterator::Next() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001322 // Run through the bytes until we reach one with a least significant
1323 // bit of zero (marks the end).
1324 uint32_t bits = 0;
1325 for (int i = 0; true; i += 7) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001326 ASSERT(HasNext());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001327 uint8_t next = buffer_->get(index_++);
1328 bits |= (next >> 1) << i;
1329 if ((next & 1) == 0) break;
1330 }
1331 // The bits encode the sign in the least significant bit.
1332 bool is_negative = (bits & 1) == 1;
1333 int32_t result = bits >> 1;
1334 return is_negative ? -result : result;
1335}
1336
1337
1338Handle<ByteArray> TranslationBuffer::CreateByteArray() {
1339 int length = contents_.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001340 Handle<ByteArray> result =
1341 Isolate::Current()->factory()->NewByteArray(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001342 memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
1343 return result;
1344}
1345
1346
ulan@chromium.org967e2702012-02-28 09:49:15 +00001347void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001348 buffer_->Add(CONSTRUCT_STUB_FRAME, zone());
1349 buffer_->Add(literal_id, zone());
1350 buffer_->Add(height, zone());
ulan@chromium.org967e2702012-02-28 09:49:15 +00001351}
1352
1353
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001354void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001355 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone());
1356 buffer_->Add(literal_id, zone());
1357 buffer_->Add(height, zone());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001358}
1359
1360
1361void Translation::BeginJSFrame(int node_id, int literal_id, unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001362 buffer_->Add(JS_FRAME, zone());
1363 buffer_->Add(node_id, zone());
1364 buffer_->Add(literal_id, zone());
1365 buffer_->Add(height, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001366}
1367
1368
1369void Translation::StoreRegister(Register reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001370 buffer_->Add(REGISTER, zone());
1371 buffer_->Add(reg.code(), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001372}
1373
1374
1375void Translation::StoreInt32Register(Register reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001376 buffer_->Add(INT32_REGISTER, zone());
1377 buffer_->Add(reg.code(), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001378}
1379
1380
1381void Translation::StoreDoubleRegister(DoubleRegister reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001382 buffer_->Add(DOUBLE_REGISTER, zone());
1383 buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001384}
1385
1386
1387void Translation::StoreStackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001388 buffer_->Add(STACK_SLOT, zone());
1389 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001390}
1391
1392
1393void Translation::StoreInt32StackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001394 buffer_->Add(INT32_STACK_SLOT, zone());
1395 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001396}
1397
1398
1399void Translation::StoreDoubleStackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001400 buffer_->Add(DOUBLE_STACK_SLOT, zone());
1401 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001402}
1403
1404
1405void Translation::StoreLiteral(int literal_id) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001406 buffer_->Add(LITERAL, zone());
1407 buffer_->Add(literal_id, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001408}
1409
1410
1411void Translation::StoreArgumentsObject() {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001412 buffer_->Add(ARGUMENTS_OBJECT, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001413}
1414
1415
1416void Translation::MarkDuplicate() {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001417 buffer_->Add(DUPLICATE, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001418}
1419
1420
1421int Translation::NumberOfOperandsFor(Opcode opcode) {
1422 switch (opcode) {
1423 case ARGUMENTS_OBJECT:
1424 case DUPLICATE:
1425 return 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001426 case REGISTER:
1427 case INT32_REGISTER:
1428 case DOUBLE_REGISTER:
1429 case STACK_SLOT:
1430 case INT32_STACK_SLOT:
1431 case DOUBLE_STACK_SLOT:
1432 case LITERAL:
1433 return 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001434 case BEGIN:
1435 case ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00001436 case CONSTRUCT_STUB_FRAME:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001437 return 2;
1438 case JS_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001439 return 3;
1440 }
1441 UNREACHABLE();
1442 return -1;
1443}
1444
1445
whesse@chromium.org7b260152011-06-20 15:33:18 +00001446#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001447
1448const char* Translation::StringFor(Opcode opcode) {
1449 switch (opcode) {
1450 case BEGIN:
1451 return "BEGIN";
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001452 case JS_FRAME:
1453 return "JS_FRAME";
1454 case ARGUMENTS_ADAPTOR_FRAME:
1455 return "ARGUMENTS_ADAPTOR_FRAME";
ulan@chromium.org967e2702012-02-28 09:49:15 +00001456 case CONSTRUCT_STUB_FRAME:
1457 return "CONSTRUCT_STUB_FRAME";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001458 case REGISTER:
1459 return "REGISTER";
1460 case INT32_REGISTER:
1461 return "INT32_REGISTER";
1462 case DOUBLE_REGISTER:
1463 return "DOUBLE_REGISTER";
1464 case STACK_SLOT:
1465 return "STACK_SLOT";
1466 case INT32_STACK_SLOT:
1467 return "INT32_STACK_SLOT";
1468 case DOUBLE_STACK_SLOT:
1469 return "DOUBLE_STACK_SLOT";
1470 case LITERAL:
1471 return "LITERAL";
1472 case ARGUMENTS_OBJECT:
1473 return "ARGUMENTS_OBJECT";
1474 case DUPLICATE:
1475 return "DUPLICATE";
1476 }
1477 UNREACHABLE();
1478 return "";
1479}
1480
1481#endif
1482
1483
1484DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001485 GlobalHandles* global_handles = Isolate::Current()->global_handles();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001486 // Globalize the code object and make it weak.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001487 code_ = Handle<Code>::cast(global_handles->Create(code));
1488 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
1489 this,
1490 Deoptimizer::HandleWeakDeoptimizedCode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001491}
1492
1493
1494DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001495 GlobalHandles* global_handles = Isolate::Current()->global_handles();
1496 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500// We can't intermix stack decoding and allocations because
1501// deoptimization infrastracture is not GC safe.
1502// Thus we build a temporary structure in malloced space.
1503SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
1504 DeoptimizationInputData* data,
1505 JavaScriptFrame* frame) {
1506 Translation::Opcode opcode =
1507 static_cast<Translation::Opcode>(iterator->Next());
1508
1509 switch (opcode) {
1510 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001511 case Translation::JS_FRAME:
1512 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00001513 case Translation::CONSTRUCT_STUB_FRAME:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001514 // Peeled off before getting here.
1515 break;
1516
1517 case Translation::ARGUMENTS_OBJECT:
1518 // This can be only emitted for local slots not for argument slots.
1519 break;
1520
1521 case Translation::REGISTER:
1522 case Translation::INT32_REGISTER:
1523 case Translation::DOUBLE_REGISTER:
1524 case Translation::DUPLICATE:
1525 // We are at safepoint which corresponds to call. All registers are
1526 // saved by caller so there would be no live registers at this
1527 // point. Thus these translation commands should not be used.
1528 break;
1529
1530 case Translation::STACK_SLOT: {
1531 int slot_index = iterator->Next();
1532 Address slot_addr = SlotAddress(frame, slot_index);
1533 return SlotRef(slot_addr, SlotRef::TAGGED);
1534 }
1535
1536 case Translation::INT32_STACK_SLOT: {
1537 int slot_index = iterator->Next();
1538 Address slot_addr = SlotAddress(frame, slot_index);
1539 return SlotRef(slot_addr, SlotRef::INT32);
1540 }
1541
1542 case Translation::DOUBLE_STACK_SLOT: {
1543 int slot_index = iterator->Next();
1544 Address slot_addr = SlotAddress(frame, slot_index);
1545 return SlotRef(slot_addr, SlotRef::DOUBLE);
1546 }
1547
1548 case Translation::LITERAL: {
1549 int literal_index = iterator->Next();
1550 return SlotRef(data->LiteralArray()->get(literal_index));
1551 }
1552 }
1553
1554 UNREACHABLE();
1555 return SlotRef();
1556}
1557
1558
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001559void SlotRef::ComputeSlotsForArguments(Vector<SlotRef>* args_slots,
1560 TranslationIterator* it,
1561 DeoptimizationInputData* data,
1562 JavaScriptFrame* frame) {
1563 // Process the translation commands for the arguments.
1564
1565 // Skip the translation command for the receiver.
1566 it->Skip(Translation::NumberOfOperandsFor(
1567 static_cast<Translation::Opcode>(it->Next())));
1568
1569 // Compute slots for arguments.
1570 for (int i = 0; i < args_slots->length(); ++i) {
1571 (*args_slots)[i] = ComputeSlotForNextArgument(it, data, frame);
1572 }
1573}
1574
1575
1576Vector<SlotRef> SlotRef::ComputeSlotMappingForArguments(
1577 JavaScriptFrame* frame,
1578 int inlined_jsframe_index,
1579 int formal_parameter_count) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001580 AssertNoAllocation no_gc;
1581 int deopt_index = AstNode::kNoNumber;
1582 DeoptimizationInputData* data =
1583 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
1584 TranslationIterator it(data->TranslationByteArray(),
1585 data->TranslationIndex(deopt_index)->value());
1586 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1587 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001588 it.Next(); // Drop frame count.
1589 int jsframe_count = it.Next();
1590 USE(jsframe_count);
1591 ASSERT(jsframe_count > inlined_jsframe_index);
1592 int jsframes_to_skip = inlined_jsframe_index;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001593 while (true) {
1594 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001595 if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) {
1596 if (jsframes_to_skip == 0) {
1597 ASSERT(Translation::NumberOfOperandsFor(opcode) == 2);
1598
1599 it.Skip(1); // literal id
1600 int height = it.Next();
1601
1602 // We reached the arguments adaptor frame corresponding to the
1603 // inlined function in question. Number of arguments is height - 1.
1604 Vector<SlotRef> args_slots =
1605 Vector<SlotRef>::New(height - 1); // Minus receiver.
1606 ComputeSlotsForArguments(&args_slots, &it, data, frame);
1607 return args_slots;
1608 }
1609 } else if (opcode == Translation::JS_FRAME) {
1610 if (jsframes_to_skip == 0) {
1611 // Skip over operands to advance to the next opcode.
1612 it.Skip(Translation::NumberOfOperandsFor(opcode));
1613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001614 // We reached the frame corresponding to the inlined function
1615 // in question. Process the translation commands for the
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001616 // arguments. Number of arguments is equal to the number of
1617 // format parameter count.
1618 Vector<SlotRef> args_slots =
1619 Vector<SlotRef>::New(formal_parameter_count);
1620 ComputeSlotsForArguments(&args_slots, &it, data, frame);
1621 return args_slots;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001622 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001623 jsframes_to_skip--;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001624 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001625
1626 // Skip over operands to advance to the next opcode.
1627 it.Skip(Translation::NumberOfOperandsFor(opcode));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001628 }
1629
1630 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001631 return Vector<SlotRef>();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001632}
1633
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001634#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001635
ulan@chromium.org967e2702012-02-28 09:49:15 +00001636DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
1637 int frame_index,
1638 bool has_arguments_adaptor,
1639 bool has_construct_stub) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001640 FrameDescription* output_frame = deoptimizer->output_[frame_index];
ulan@chromium.org967e2702012-02-28 09:49:15 +00001641 function_ = output_frame->GetFunction();
1642 has_construct_stub_ = has_construct_stub;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001643 expression_count_ = output_frame->GetExpressionCount();
1644 expression_stack_ = new Object*[expression_count_];
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001645 // Get the source position using the unoptimized code.
1646 Address pc = reinterpret_cast<Address>(output_frame->GetPc());
1647 Code* code = Code::cast(Isolate::Current()->heap()->FindCodeObject(pc));
1648 source_position_ = code->SourcePosition(pc);
1649
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001650 for (int i = 0; i < expression_count_; i++) {
1651 SetExpression(i, output_frame->GetExpression(i));
1652 }
1653
1654 if (has_arguments_adaptor) {
1655 output_frame = deoptimizer->output_[frame_index - 1];
1656 ASSERT(output_frame->GetFrameType() == StackFrame::ARGUMENTS_ADAPTOR);
1657 }
1658
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001659 parameters_count_ = output_frame->ComputeParametersCount();
1660 parameters_ = new Object*[parameters_count_];
1661 for (int i = 0; i < parameters_count_; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001662 SetParameter(i, output_frame->GetParameter(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001663 }
1664}
1665
1666
1667DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001668 delete[] expression_stack_;
1669 delete[] parameters_;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001670}
1671
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001672
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001673void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001674 v->VisitPointer(BitCast<Object**>(&function_));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001675 v->VisitPointers(parameters_, parameters_ + parameters_count_);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001676 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
1677}
1678
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001679#endif // ENABLE_DEBUGGER_SUPPORT
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001680
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001681} } // namespace v8::internal