blob: c0b5945540c0da77e5b0f1f1bc3cfb25bee6ac70 [file] [log] [blame]
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001// Copyright 2013 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
ulan@chromium.org56c14af2012-09-20 12:51:09 +000030#include "accessors.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000031#include "codegen.h"
32#include "deoptimizer.h"
33#include "disasm.h"
34#include "full-codegen.h"
35#include "global-handles.h"
36#include "macro-assembler.h"
37#include "prettyprinter.h"
38
39
40namespace v8 {
41namespace internal {
42
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000043DeoptimizerData::DeoptimizerData() {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000044 eager_deoptimization_entry_code_entries_ = -1;
45 lazy_deoptimization_entry_code_entries_ = -1;
46 size_t deopt_table_size = Deoptimizer::GetMaxDeoptTableSize();
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +000047 MemoryAllocator* allocator = Isolate::Current()->memory_allocator();
48 size_t initial_commit_size = OS::CommitPageSize();
49 eager_deoptimization_entry_code_ =
50 allocator->AllocateChunk(deopt_table_size,
51 initial_commit_size,
52 EXECUTABLE,
53 NULL);
54 lazy_deoptimization_entry_code_ =
55 allocator->AllocateChunk(deopt_table_size,
56 initial_commit_size,
57 EXECUTABLE,
58 NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000059 current_ = NULL;
60 deoptimizing_code_list_ = NULL;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000061#ifdef ENABLE_DEBUGGER_SUPPORT
62 deoptimized_frame_info_ = NULL;
63#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000065
66
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067DeoptimizerData::~DeoptimizerData() {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +000068 Isolate::Current()->memory_allocator()->Free(
69 eager_deoptimization_entry_code_);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000070 eager_deoptimization_entry_code_ = NULL;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +000071 Isolate::Current()->memory_allocator()->Free(
72 lazy_deoptimization_entry_code_);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000073 lazy_deoptimization_entry_code_ = NULL;
74
danno@chromium.org72204d52012-10-31 10:02:10 +000075 DeoptimizingCodeListNode* current = deoptimizing_code_list_;
76 while (current != NULL) {
77 DeoptimizingCodeListNode* prev = current;
78 current = current->next();
79 delete prev;
80 }
81 deoptimizing_code_list_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000082}
83
ricow@chromium.org4f693d62011-07-04 14:01:31 +000084
85#ifdef ENABLE_DEBUGGER_SUPPORT
86void DeoptimizerData::Iterate(ObjectVisitor* v) {
87 if (deoptimized_frame_info_ != NULL) {
88 deoptimized_frame_info_->Iterate(v);
89 }
90}
91#endif
92
93
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000094Code* DeoptimizerData::FindDeoptimizingCode(Address addr) {
95 for (DeoptimizingCodeListNode* node = deoptimizing_code_list_;
96 node != NULL;
97 node = node->next()) {
98 if (node->code()->contains(addr)) return *node->code();
99 }
100 return NULL;
101}
102
103
104void DeoptimizerData::RemoveDeoptimizingCode(Code* code) {
105 for (DeoptimizingCodeListNode *prev = NULL, *cur = deoptimizing_code_list_;
106 cur != NULL;
107 prev = cur, cur = cur->next()) {
108 if (*cur->code() == code) {
109 if (prev == NULL) {
110 deoptimizing_code_list_ = cur->next();
111 } else {
112 prev->set_next(cur->next());
113 }
114 delete cur;
115 return;
116 }
117 }
118 // Deoptimizing code is removed through weak callback. Each object is expected
119 // to be removed once and only once.
120 UNREACHABLE();
121}
122
123
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000124// We rely on this function not causing a GC. It is called from generated code
125// without having a real stack frame in place.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000126Deoptimizer* Deoptimizer::New(JSFunction* function,
127 BailoutType type,
128 unsigned bailout_id,
129 Address from,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130 int fp_to_sp_delta,
131 Isolate* isolate) {
132 ASSERT(isolate == Isolate::Current());
133 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
134 function,
135 type,
136 bailout_id,
137 from,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000138 fp_to_sp_delta,
139 NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000140 ASSERT(isolate->deoptimizer_data()->current_ == NULL);
141 isolate->deoptimizer_data()->current_ = deoptimizer;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000142 return deoptimizer;
143}
144
145
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000146// No larger than 2K on all platforms
147static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
148
149
150size_t Deoptimizer::GetMaxDeoptTableSize() {
151 int entries_size =
152 Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
153 int commit_page_size = static_cast<int>(OS::CommitPageSize());
154 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
155 commit_page_size) + 1;
156 return static_cast<size_t>(commit_page_size * page_count);
157}
158
159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
161 ASSERT(isolate == Isolate::Current());
162 Deoptimizer* result = isolate->deoptimizer_data()->current_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000163 ASSERT(result != NULL);
164 result->DeleteFrameDescriptions();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000165 isolate->deoptimizer_data()->current_ = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000166 return result;
167}
168
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000169
170int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) {
171 if (jsframe_index == 0) return 0;
172
173 int frame_index = 0;
174 while (jsframe_index >= 0) {
175 FrameDescription* frame = output_[frame_index];
176 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) {
177 jsframe_index--;
178 }
179 frame_index++;
180 }
181
182 return frame_index - 1;
183}
184
185
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000186#ifdef ENABLE_DEBUGGER_SUPPORT
187DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
188 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000189 int jsframe_index,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000190 Isolate* isolate) {
191 ASSERT(isolate == Isolate::Current());
192 ASSERT(frame->is_optimized());
193 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
194
195 // Get the function and code from the frame.
196 JSFunction* function = JSFunction::cast(frame->function());
197 Code* code = frame->LookupCode();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000198
199 // Locate the deoptimization point in the code. As we are at a call the
200 // return address must be at a place in the code with deoptimization support.
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000201 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
202 int deoptimization_index = safepoint_entry.deoptimization_index();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000203 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
204
205 // Always use the actual stack slots when calculating the fp to sp
206 // delta adding two for the function and context.
207 unsigned stack_slots = code->stack_slots();
208 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
209
210 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
211 function,
212 Deoptimizer::DEBUGGER,
213 deoptimization_index,
214 frame->pc(),
215 fp_to_sp_delta,
216 code);
217 Address tos = frame->fp() - fp_to_sp_delta;
218 deoptimizer->FillInputFrame(tos, frame);
219
220 // Calculate the output frames.
221 Deoptimizer::ComputeOutputFrames(deoptimizer);
222
223 // Create the GC safe output frame information and register it for GC
224 // handling.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000225 ASSERT_LT(jsframe_index, deoptimizer->jsframe_count());
226
227 // Convert JS frame index into frame index.
228 int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index);
229
230 bool has_arguments_adaptor =
231 frame_index > 0 &&
232 deoptimizer->output_[frame_index - 1]->GetFrameType() ==
233 StackFrame::ARGUMENTS_ADAPTOR;
234
ulan@chromium.org967e2702012-02-28 09:49:15 +0000235 int construct_offset = has_arguments_adaptor ? 2 : 1;
236 bool has_construct_stub =
237 frame_index >= construct_offset &&
238 deoptimizer->output_[frame_index - construct_offset]->GetFrameType() ==
239 StackFrame::CONSTRUCT;
240
241 DeoptimizedFrameInfo* info = new DeoptimizedFrameInfo(deoptimizer,
242 frame_index,
243 has_arguments_adaptor,
244 has_construct_stub);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000245 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
246
247 // Get the "simulated" top and size for the requested frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000248 FrameDescription* parameters_frame =
249 deoptimizer->output_[
250 has_arguments_adaptor ? (frame_index - 1) : frame_index];
251
252 uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize;
253 Address parameters_top = reinterpret_cast<Address>(
254 parameters_frame->GetTop() + (parameters_frame->GetFrameSize() -
255 parameters_size));
256
257 uint32_t expressions_size = info->expression_count() * kPointerSize;
258 Address expressions_top = reinterpret_cast<Address>(
259 deoptimizer->output_[frame_index]->GetTop());
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000260
261 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
262 deoptimizer->DeleteFrameDescriptions();
263
264 // Allocate a heap number for the doubles belonging to this frame.
265 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000266 parameters_top, parameters_size, expressions_top, expressions_size, info);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000267
268 // Finished using the deoptimizer instance.
269 delete deoptimizer;
270
271 return info;
272}
273
274
275void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
276 Isolate* isolate) {
277 ASSERT(isolate == Isolate::Current());
278 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
279 delete info;
280 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
281}
282#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000283
284void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
285 int count,
286 BailoutType type) {
287 TableEntryGenerator generator(masm, type, count);
288 generator.Generate();
289}
290
291
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000292void Deoptimizer::VisitAllOptimizedFunctionsForContext(
293 Context* context, OptimizedFunctionVisitor* visitor) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000294 Isolate* isolate = context->GetIsolate();
295 ZoneScope zone_scope(isolate->runtime_zone(), DELETE_ON_EXIT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000296 AssertNoAllocation no_allocation;
297
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 ASSERT(context->IsNativeContext());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000299
300 visitor->EnterContext(context);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000301
302 // Create a snapshot of the optimized functions list. This is needed because
303 // visitors might remove more than one link from the list at once.
304 ZoneList<JSFunction*> snapshot(1, isolate->runtime_zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000305 Object* element = context->OptimizedFunctionsListHead();
306 while (!element->IsUndefined()) {
307 JSFunction* element_function = JSFunction::cast(element);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000308 snapshot.Add(element_function, isolate->runtime_zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 element = element_function->next_function_link();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000310 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000311
312 // Run through the snapshot of optimized functions and visit them.
313 for (int i = 0; i < snapshot.length(); ++i) {
314 visitor->VisitFunction(snapshot.at(i));
315 }
316
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000317 visitor->LeaveContext(context);
318}
319
320
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000321void Deoptimizer::VisitAllOptimizedFunctions(
322 OptimizedFunctionVisitor* visitor) {
323 AssertNoAllocation no_allocation;
324
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000325 // Run through the list of all native contexts and deoptimize.
326 Object* context = Isolate::Current()->heap()->native_contexts_list();
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000327 while (!context->IsUndefined()) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000328 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000329 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000330 }
331}
332
333
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000334// Removes the functions selected by the given filter from the optimized
335// function list of the given context and partitions the removed functions
336// into one or more lists such that all functions in a list share the same
337// code. The head of each list is written in the deoptimizing_functions field
338// of the corresponding code object.
339// The found code objects are returned in the given zone list.
340static void PartitionOptimizedFunctions(Context* context,
341 OptimizedFunctionFilter* filter,
342 ZoneList<Code*>* partitions,
343 Zone* zone,
344 Object* undefined) {
345 AssertNoAllocation no_allocation;
346 Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST);
347 Object* remainder_head = undefined;
348 Object* remainder_tail = undefined;
349 ASSERT_EQ(0, partitions->length());
350 while (current != undefined) {
351 JSFunction* function = JSFunction::cast(current);
352 current = function->next_function_link();
353 if (filter->TakeFunction(function)) {
354 Code* code = function->code();
355 if (code->deoptimizing_functions() == undefined) {
356 partitions->Add(code, zone);
357 } else {
358 ASSERT(partitions->Contains(code));
359 }
360 function->set_next_function_link(code->deoptimizing_functions());
361 code->set_deoptimizing_functions(function);
362 } else {
363 if (remainder_head == undefined) {
364 remainder_head = function;
365 } else {
366 JSFunction::cast(remainder_tail)->set_next_function_link(function);
367 }
368 remainder_tail = function;
369 }
370 }
371 if (remainder_tail != undefined) {
372 JSFunction::cast(remainder_tail)->set_next_function_link(undefined);
373 }
374 context->set(Context::OPTIMIZED_FUNCTIONS_LIST, remainder_head);
375}
376
377
378class DeoptimizeAllFilter : public OptimizedFunctionFilter {
379 public:
380 virtual bool TakeFunction(JSFunction* function) {
381 return true;
382 }
383};
384
385
386class DeoptimizeWithMatchingCodeFilter : public OptimizedFunctionFilter {
387 public:
388 explicit DeoptimizeWithMatchingCodeFilter(Code* code) : code_(code) {}
389 virtual bool TakeFunction(JSFunction* function) {
390 return function->code() == code_;
391 }
392 private:
393 Code* code_;
394};
395
396
397void Deoptimizer::DeoptimizeAll() {
398 AssertNoAllocation no_allocation;
399
400 if (FLAG_trace_deopt) {
401 PrintF("[deoptimize all contexts]\n");
402 }
403
404 DeoptimizeAllFilter filter;
405 DeoptimizeAllFunctionsWith(&filter);
406}
407
408
409void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
410 AssertNoAllocation no_allocation;
411 DeoptimizeAllFilter filter;
412 if (object->IsJSGlobalProxy()) {
413 Object* proto = object->GetPrototype();
414 ASSERT(proto->IsJSGlobalObject());
415 DeoptimizeAllFunctionsForContext(
416 GlobalObject::cast(proto)->native_context(), &filter);
417 } else if (object->IsGlobalObject()) {
418 DeoptimizeAllFunctionsForContext(
419 GlobalObject::cast(object)->native_context(), &filter);
420 }
421}
422
423
424void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
425 if (!function->IsOptimized()) return;
426 Code* code = function->code();
427 Context* context = function->context()->native_context();
428 Isolate* isolate = context->GetIsolate();
429 Object* undefined = isolate->heap()->undefined_value();
430 Zone* zone = isolate->runtime_zone();
431 ZoneScope zone_scope(zone, DELETE_ON_EXIT);
432 ZoneList<Code*> codes(1, zone);
433 DeoptimizeWithMatchingCodeFilter filter(code);
434 PartitionOptimizedFunctions(context, &filter, &codes, zone, undefined);
435 ASSERT_EQ(1, codes.length());
436 DeoptimizeFunctionWithPreparedFunctionList(
437 JSFunction::cast(codes.at(0)->deoptimizing_functions()));
438 codes.at(0)->set_deoptimizing_functions(undefined);
439}
440
441
442void Deoptimizer::DeoptimizeAllFunctionsForContext(
443 Context* context, OptimizedFunctionFilter* filter) {
444 ASSERT(context->IsNativeContext());
445 Isolate* isolate = context->GetIsolate();
446 Object* undefined = isolate->heap()->undefined_value();
447 Zone* zone = isolate->runtime_zone();
448 ZoneScope zone_scope(zone, DELETE_ON_EXIT);
449 ZoneList<Code*> codes(1, zone);
450 PartitionOptimizedFunctions(context, filter, &codes, zone, undefined);
451 for (int i = 0; i < codes.length(); ++i) {
452 DeoptimizeFunctionWithPreparedFunctionList(
453 JSFunction::cast(codes.at(i)->deoptimizing_functions()));
454 codes.at(i)->set_deoptimizing_functions(undefined);
455 }
456}
457
458
459void Deoptimizer::DeoptimizeAllFunctionsWith(OptimizedFunctionFilter* filter) {
460 AssertNoAllocation no_allocation;
461
462 // Run through the list of all native contexts and deoptimize.
463 Object* context = Isolate::Current()->heap()->native_contexts_list();
464 while (!context->IsUndefined()) {
465 DeoptimizeAllFunctionsForContext(Context::cast(context), filter);
466 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
467 }
468}
469
470
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000471void Deoptimizer::HandleWeakDeoptimizedCode(v8::Isolate* isolate,
472 v8::Persistent<v8::Value> obj,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000473 void* parameter) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000474 DeoptimizingCodeListNode* node =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000475 reinterpret_cast<DeoptimizingCodeListNode*>(parameter);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000476 DeoptimizerData* data =
477 reinterpret_cast<Isolate*>(isolate)->deoptimizer_data();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000478 data->RemoveDeoptimizingCode(*node->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000479#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000480 for (DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
481 current != NULL;
482 current = current->next()) {
483 ASSERT(current != node);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000484 }
485#endif
486}
487
488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000489void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000490 deoptimizer->DoComputeOutputFrames();
491}
492
493
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000494bool Deoptimizer::TraceEnabledFor(BailoutType deopt_type,
495 StackFrame::Type frame_type) {
496 switch (deopt_type) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000497 case EAGER:
498 case LAZY:
499 case DEBUGGER:
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000500 return (frame_type == StackFrame::STUB)
501 ? FLAG_trace_stub_failures
502 : FLAG_trace_deopt;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000503 case OSR:
504 return FLAG_trace_osr;
505 }
506 UNREACHABLE();
507 return false;
508}
509
510
511const char* Deoptimizer::MessageFor(BailoutType type) {
512 switch (type) {
513 case EAGER:
514 case LAZY:
515 return "DEOPT";
516 case DEBUGGER:
517 return "DEOPT FOR DEBUGGER";
518 case OSR:
519 return "OSR";
520 }
521 UNREACHABLE();
ulan@chromium.org4121f232012-12-27 15:57:11 +0000522 return NULL;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000523}
524
525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526Deoptimizer::Deoptimizer(Isolate* isolate,
527 JSFunction* function,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000528 BailoutType type,
529 unsigned bailout_id,
530 Address from,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000531 int fp_to_sp_delta,
532 Code* optimized_code)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 : isolate_(isolate),
534 function_(function),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000535 bailout_id_(bailout_id),
536 bailout_type_(type),
537 from_(from),
538 fp_to_sp_delta_(fp_to_sp_delta),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000539 has_alignment_padding_(0),
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000540 input_(NULL),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000541 output_count_(0),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000542 jsframe_count_(0),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000543 output_(NULL),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000544 deferred_arguments_objects_values_(0),
545 deferred_arguments_objects_(0),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000546 deferred_heap_numbers_(0),
547 trace_(false) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000548 // For COMPILED_STUBs called from builtins, the function pointer is a SMI
549 // indicating an internal frame.
550 if (function->IsSmi()) {
551 function = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000552 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000553 if (function != NULL && function->IsOptimized()) {
554 function->shared()->increment_deopt_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000555 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000556 compiled_code_ = FindOptimizedCode(function, optimized_code);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000557 StackFrame::Type frame_type = function == NULL
558 ? StackFrame::STUB
559 : StackFrame::JAVA_SCRIPT;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000560 trace_ = TraceEnabledFor(type, frame_type);
561 if (trace_) Trace();
562 ASSERT(HEAP->allow_allocation(false));
563 unsigned size = ComputeInputFrameSize();
564 input_ = new(size) FrameDescription(size, function);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000565 input_->SetFrameType(frame_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000566}
567
568
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000569Code* Deoptimizer::FindOptimizedCode(JSFunction* function,
570 Code* optimized_code) {
571 switch (bailout_type_) {
572 case Deoptimizer::EAGER:
573 ASSERT(from_ == NULL);
574 return function->code();
575 case Deoptimizer::LAZY: {
576 Code* compiled_code =
577 isolate_->deoptimizer_data()->FindDeoptimizingCode(from_);
578 return (compiled_code == NULL)
579 ? static_cast<Code*>(isolate_->heap()->FindCodeObject(from_))
580 : compiled_code;
581 }
582 case Deoptimizer::OSR: {
583 // The function has already been optimized and we're transitioning
584 // from the unoptimized shared version to the optimized one in the
585 // function. The return address (from_) points to unoptimized code.
586 Code* compiled_code = function->code();
587 ASSERT(compiled_code->kind() == Code::OPTIMIZED_FUNCTION);
588 ASSERT(!compiled_code->contains(from_));
589 return compiled_code;
590 }
591 case Deoptimizer::DEBUGGER:
592 ASSERT(optimized_code->contains(from_));
593 return optimized_code;
594 }
595 UNREACHABLE();
596 return NULL;
597}
598
599
600void Deoptimizer::Trace() {
601 PrintF("**** %s: ", Deoptimizer::MessageFor(bailout_type_));
602 PrintFunctionName();
603 PrintF(" at id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
604 bailout_id_,
605 reinterpret_cast<intptr_t>(from_),
606 fp_to_sp_delta_ - (2 * kPointerSize));
607 if (bailout_type_ == EAGER) compiled_code_->PrintDeoptLocation(bailout_id_);
608}
609
610
611void Deoptimizer::PrintFunctionName() {
612 if (function_->IsJSFunction()) {
613 function_->PrintName();
614 } else {
615 PrintF("%s", Code::Kind2String(compiled_code_->kind()));
616 }
617}
618
619
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000620Deoptimizer::~Deoptimizer() {
621 ASSERT(input_ == NULL && output_ == NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000622}
623
624
625void Deoptimizer::DeleteFrameDescriptions() {
626 delete input_;
627 for (int i = 0; i < output_count_; ++i) {
628 if (output_[i] != input_) delete output_[i];
629 }
630 delete[] output_;
631 input_ = NULL;
632 output_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 ASSERT(!HEAP->allow_allocation(true));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000634}
635
636
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000637Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
638 int id,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000639 BailoutType type,
640 GetEntryMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000641 ASSERT(id >= 0);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000642 if (id >= kMaxNumberOfEntries) return NULL;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000643 MemoryChunk* base = NULL;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000644 if (mode == ENSURE_ENTRY_CODE) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000645 EnsureCodeForDeoptimizationEntry(isolate, type, id);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000646 } else {
647 ASSERT(mode == CALCULATE_ENTRY_ADDRESS);
648 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000649 DeoptimizerData* data = isolate->deoptimizer_data();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000650 if (type == EAGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000651 base = data->eager_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000652 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000653 base = data->lazy_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000654 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000655 return base->area_start() + (id * table_entry_size_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000656}
657
658
659int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000660 MemoryChunk* base = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000661 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000662 if (type == EAGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000663 base = data->eager_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000664 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000665 base = data->lazy_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000666 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000667 Address start = base->area_start();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000668 if (base == NULL ||
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000669 addr < start ||
670 addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000671 return kNotDeoptimizationEntry;
672 }
673 ASSERT_EQ(0,
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000674 static_cast<int>(addr - start) % table_entry_size_);
675 return static_cast<int>(addr - start) / table_entry_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000676}
677
678
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000679int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000680 BailoutId id,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000681 SharedFunctionInfo* shared) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000682 // TODO(kasperl): For now, we do a simple linear search for the PC
683 // offset associated with the given node id. This should probably be
684 // changed to a binary search.
685 int length = data->DeoptPoints();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000686 for (int i = 0; i < length; i++) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000687 if (data->AstId(i) == id) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000688 return data->PcAndState(i)->value();
689 }
690 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000691 PrintF("[couldn't find pc offset for node=%d]\n", id.ToInt());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000692 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
693 // Print the source code if available.
694 HeapStringAllocator string_allocator;
695 StringStream stream(&string_allocator);
696 shared->SourceCodePrint(&stream, -1);
697 PrintF("[source:\n%s\n]", *stream.ToCString());
698
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000699 FATAL("unable to find pc offset during deoptimization");
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000700 return -1;
701}
702
703
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000704int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000705 int length = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000706 DeoptimizingCodeListNode* node =
707 isolate->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000708 while (node != NULL) {
709 length++;
710 node = node->next();
711 }
712 return length;
713}
714
715
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000716// We rely on this function not causing a GC. It is called from generated code
717// without having a real stack frame in place.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000718void Deoptimizer::DoComputeOutputFrames() {
719 if (bailout_type_ == OSR) {
720 DoComputeOsrOutputFrame();
721 return;
722 }
723
724 // Print some helpful diagnostic information.
725 int64_t start = OS::Ticks();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000726 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000727 PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
728 (bailout_type_ == LAZY ? " (lazy)" : ""),
729 reinterpret_cast<intptr_t>(function_));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000730 PrintFunctionName();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000731 PrintF(" @%d]\n", bailout_id_);
732 }
733
734 // Determine basic deoptimization information. The optimized frame is
735 // described by the input data.
736 DeoptimizationInputData* input_data =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000737 DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000738 BailoutId node_id = input_data->AstId(bailout_id_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000739 ByteArray* translations = input_data->TranslationByteArray();
740 unsigned translation_index =
741 input_data->TranslationIndex(bailout_id_)->value();
742
743 // Do the input frame to output frame(s) translation.
744 TranslationIterator iterator(translations, translation_index);
745 Translation::Opcode opcode =
746 static_cast<Translation::Opcode>(iterator.Next());
747 ASSERT(Translation::BEGIN == opcode);
748 USE(opcode);
749 // Read the number of output frames and allocate an array for their
750 // descriptions.
751 int count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000752 iterator.Next(); // Drop JS frames count.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000753 ASSERT(output_ == NULL);
754 output_ = new FrameDescription*[count];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000755 for (int i = 0; i < count; ++i) {
756 output_[i] = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000757 }
758 output_count_ = count;
759
760 // Translate each output frame.
761 for (int i = 0; i < count; ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000762 // Read the ast node id, function, and frame height for this output frame.
763 Translation::Opcode opcode =
764 static_cast<Translation::Opcode>(iterator.Next());
765 switch (opcode) {
766 case Translation::JS_FRAME:
767 DoComputeJSFrame(&iterator, i);
768 jsframe_count_++;
769 break;
770 case Translation::ARGUMENTS_ADAPTOR_FRAME:
771 DoComputeArgumentsAdaptorFrame(&iterator, i);
772 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000773 case Translation::CONSTRUCT_STUB_FRAME:
774 DoComputeConstructStubFrame(&iterator, i);
775 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000776 case Translation::GETTER_STUB_FRAME:
777 DoComputeAccessorStubFrame(&iterator, i, false);
778 break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000779 case Translation::SETTER_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000780 DoComputeAccessorStubFrame(&iterator, i, true);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000781 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000782 case Translation::COMPILED_STUB_FRAME:
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000783 DoComputeCompiledStubFrame(&iterator, i);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000784 break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000785 case Translation::BEGIN:
786 case Translation::REGISTER:
787 case Translation::INT32_REGISTER:
788 case Translation::UINT32_REGISTER:
789 case Translation::DOUBLE_REGISTER:
790 case Translation::STACK_SLOT:
791 case Translation::INT32_STACK_SLOT:
792 case Translation::UINT32_STACK_SLOT:
793 case Translation::DOUBLE_STACK_SLOT:
794 case Translation::LITERAL:
795 case Translation::ARGUMENTS_OBJECT:
796 case Translation::DUPLICATE:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000797 default:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000798 UNREACHABLE();
799 break;
800 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000801 }
802
803 // Print some helpful diagnostic information.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000804 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000805 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
806 int index = output_count_ - 1; // Index of the topmost frame.
807 JSFunction* function = output_[index]->GetFunction();
808 PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
809 reinterpret_cast<intptr_t>(function));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000810 if (function != NULL) function->PrintName();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000811 PrintF(" => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000812 " took %0.3f ms]\n",
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000813 node_id.ToInt(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000814 output_[index]->GetPc(),
815 FullCodeGenerator::State2String(
816 static_cast<FullCodeGenerator::State>(
817 output_[index]->GetState()->value())),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000818 has_alignment_padding_ ? "with padding" : "no padding",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000819 ms);
820 }
821}
822
823
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000824void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
825 int frame_index) {
826 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
827 unsigned height = iterator->Next();
828 unsigned height_in_bytes = height * kPointerSize;
829 if (trace_) {
830 PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
831 }
832
833 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
834 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
835
836 // Allocate and store the output frame description.
837 FrameDescription* output_frame =
838 new(output_frame_size) FrameDescription(output_frame_size, function);
839 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
840
841 // Arguments adaptor can not be topmost or bottommost.
842 ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
843 ASSERT(output_[frame_index] == NULL);
844 output_[frame_index] = output_frame;
845
846 // The top address of the frame is computed from the previous
847 // frame's top and this frame's size.
848 intptr_t top_address;
849 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
850 output_frame->SetTop(top_address);
851
852 // Compute the incoming parameter translation.
853 int parameter_count = height;
854 unsigned output_offset = output_frame_size;
855 for (int i = 0; i < parameter_count; ++i) {
856 output_offset -= kPointerSize;
857 DoTranslateCommand(iterator, frame_index, output_offset);
858 }
859
860 // Read caller's PC from the previous frame.
861 output_offset -= kPointerSize;
862 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
863 output_frame->SetFrameSlot(output_offset, callers_pc);
864 if (trace_) {
865 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
866 V8PRIxPTR " ; caller's pc\n",
867 top_address + output_offset, output_offset, callers_pc);
868 }
869
870 // Read caller's FP from the previous frame, and set this frame's FP.
871 output_offset -= kPointerSize;
872 intptr_t value = output_[frame_index - 1]->GetFp();
873 output_frame->SetFrameSlot(output_offset, value);
874 intptr_t fp_value = top_address + output_offset;
875 output_frame->SetFp(fp_value);
876 if (trace_) {
877 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
878 V8PRIxPTR " ; caller's fp\n",
879 fp_value, output_offset, value);
880 }
881
882 // A marker value is used in place of the context.
883 output_offset -= kPointerSize;
884 intptr_t context = reinterpret_cast<intptr_t>(
885 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
886 output_frame->SetFrameSlot(output_offset, context);
887 if (trace_) {
888 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
889 V8PRIxPTR " ; context (adaptor sentinel)\n",
890 top_address + output_offset, output_offset, context);
891 }
892
893 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
894 output_offset -= kPointerSize;
895 value = reinterpret_cast<intptr_t>(function);
896 output_frame->SetFrameSlot(output_offset, value);
897 if (trace_) {
898 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
899 V8PRIxPTR " ; function\n",
900 top_address + output_offset, output_offset, value);
901 }
902
903 // Number of incoming arguments.
904 output_offset -= kPointerSize;
905 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
906 output_frame->SetFrameSlot(output_offset, value);
907 if (trace_) {
908 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
909 V8PRIxPTR " ; argc (%d)\n",
910 top_address + output_offset, output_offset, value, height - 1);
911 }
912
913 ASSERT(0 == output_offset);
914
915 Builtins* builtins = isolate_->builtins();
916 Code* adaptor_trampoline =
917 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
918 intptr_t pc_value = reinterpret_cast<intptr_t>(
919 adaptor_trampoline->instruction_start() +
920 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
921 output_frame->SetPc(pc_value);
922}
923
924
925void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
926 int frame_index,
927 bool is_setter_stub_frame) {
928 JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
929 // The receiver (and the implicit return value, if any) are expected in
930 // registers by the LoadIC/StoreIC, so they don't belong to the output stack
931 // frame. This means that we have to use a height of 0.
932 unsigned height = 0;
933 unsigned height_in_bytes = height * kPointerSize;
934 const char* kind = is_setter_stub_frame ? "setter" : "getter";
935 if (trace_) {
936 PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
937 }
938
939 // We need 1 stack entry for the return address + 4 stack entries from
940 // StackFrame::INTERNAL (FP, context, frame type, code object, see
941 // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
942 // entry for the implicit return value, see
943 // StoreStubCompiler::CompileStoreViaSetter.
944 unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
945 unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
946 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
947
948 // Allocate and store the output frame description.
949 FrameDescription* output_frame =
950 new(output_frame_size) FrameDescription(output_frame_size, accessor);
951 output_frame->SetFrameType(StackFrame::INTERNAL);
952
953 // A frame for an accessor stub can not be the topmost or bottommost one.
954 ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
955 ASSERT(output_[frame_index] == NULL);
956 output_[frame_index] = output_frame;
957
958 // The top address of the frame is computed from the previous frame's top and
959 // this frame's size.
960 intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
961 output_frame->SetTop(top_address);
962
963 unsigned output_offset = output_frame_size;
964
965 // Read caller's PC from the previous frame.
966 output_offset -= kPointerSize;
967 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
968 output_frame->SetFrameSlot(output_offset, callers_pc);
969 if (trace_) {
970 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
971 " ; caller's pc\n",
972 top_address + output_offset, output_offset, callers_pc);
973 }
974
975 // Read caller's FP from the previous frame, and set this frame's FP.
976 output_offset -= kPointerSize;
977 intptr_t value = output_[frame_index - 1]->GetFp();
978 output_frame->SetFrameSlot(output_offset, value);
979 intptr_t fp_value = top_address + output_offset;
980 output_frame->SetFp(fp_value);
981 if (trace_) {
982 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
983 " ; caller's fp\n",
984 fp_value, output_offset, value);
985 }
986
987 // The context can be gotten from the previous frame.
988 output_offset -= kPointerSize;
989 value = output_[frame_index - 1]->GetContext();
990 output_frame->SetFrameSlot(output_offset, value);
991 if (trace_) {
992 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
993 " ; context\n",
994 top_address + output_offset, output_offset, value);
995 }
996
997 // A marker value is used in place of the function.
998 output_offset -= kPointerSize;
999 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
1000 output_frame->SetFrameSlot(output_offset, value);
1001 if (trace_) {
1002 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1003 " ; function (%s sentinel)\n",
1004 top_address + output_offset, output_offset, value, kind);
1005 }
1006
1007 // Get Code object from accessor stub.
1008 output_offset -= kPointerSize;
1009 Builtins::Name name = is_setter_stub_frame ?
1010 Builtins::kStoreIC_Setter_ForDeopt :
1011 Builtins::kLoadIC_Getter_ForDeopt;
1012 Code* accessor_stub = isolate_->builtins()->builtin(name);
1013 value = reinterpret_cast<intptr_t>(accessor_stub);
1014 output_frame->SetFrameSlot(output_offset, value);
1015 if (trace_) {
1016 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1017 " ; code object\n",
1018 top_address + output_offset, output_offset, value);
1019 }
1020
1021 // Skip receiver.
1022 Translation::Opcode opcode =
1023 static_cast<Translation::Opcode>(iterator->Next());
1024 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
1025
1026 if (is_setter_stub_frame) {
1027 // The implicit return value was part of the artificial setter stub
1028 // environment.
1029 output_offset -= kPointerSize;
1030 DoTranslateCommand(iterator, frame_index, output_offset);
1031 }
1032
1033 ASSERT(0 == output_offset);
1034
1035 Smi* offset = is_setter_stub_frame ?
1036 isolate_->heap()->setter_stub_deopt_pc_offset() :
1037 isolate_->heap()->getter_stub_deopt_pc_offset();
1038 intptr_t pc = reinterpret_cast<intptr_t>(
1039 accessor_stub->instruction_start() + offset->value());
1040 output_frame->SetPc(pc);
1041}
1042
1043
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001044void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001045 ASSERT_NE(DEBUGGER, bailout_type_);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001046
1047 // Handlify all argument object values before triggering any allocation.
1048 List<Handle<Object> > values(deferred_arguments_objects_values_.length());
1049 for (int i = 0; i < deferred_arguments_objects_values_.length(); ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001050 values.Add(Handle<Object>(deferred_arguments_objects_values_[i],
1051 isolate_));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001052 }
1053
1054 // Play it safe and clear all unhandlified values before we continue.
1055 deferred_arguments_objects_values_.Clear();
1056
1057 // Materialize all heap numbers before looking at arguments because when the
1058 // output frames are used to materialize arguments objects later on they need
1059 // to already contain valid heap numbers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001060 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
1061 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
1062 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001063 if (trace_) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001064 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
1065 reinterpret_cast<void*>(*num),
1066 d.value(),
1067 d.slot_address());
1068 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001069 Memory::Object_at(d.slot_address()) = *num;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001070 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001071
1072 // Materialize arguments objects one frame at a time.
1073 for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
1074 if (frame_index != 0) it->Advance();
1075 JavaScriptFrame* frame = it->frame();
1076 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate_);
1077 Handle<JSObject> arguments;
1078 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
1079 if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) {
1080 ArgumentsObjectMaterializationDescriptor descriptor =
1081 deferred_arguments_objects_.RemoveLast();
1082 const int length = descriptor.arguments_length();
1083 if (arguments.is_null()) {
1084 if (frame->has_adapted_arguments()) {
1085 // Use the arguments adapter frame we just built to materialize the
1086 // arguments object. FunctionGetArguments can't throw an exception,
1087 // so cast away the doubt with an assert.
1088 arguments = Handle<JSObject>(JSObject::cast(
1089 Accessors::FunctionGetArguments(*function,
1090 NULL)->ToObjectUnchecked()));
1091 values.RewindBy(length);
1092 } else {
1093 // Construct an arguments object and copy the parameters to a newly
1094 // allocated arguments object backing store.
1095 arguments =
1096 isolate_->factory()->NewArgumentsObject(function, length);
1097 Handle<FixedArray> array =
1098 isolate_->factory()->NewFixedArray(length);
1099 ASSERT(array->length() == length);
1100 for (int i = length - 1; i >= 0 ; --i) {
1101 array->set(i, *values.RemoveLast());
1102 }
1103 arguments->set_elements(*array);
1104 }
1105 }
1106 frame->SetExpression(i, *arguments);
1107 ASSERT_EQ(Memory::Object_at(descriptor.slot_address()), *arguments);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001108 if (trace_) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001109 PrintF("Materializing %sarguments object of length %d for %p: ",
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001110 frame->has_adapted_arguments() ? "(adapted) " : "",
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001111 arguments->elements()->length(),
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001112 reinterpret_cast<void*>(descriptor.slot_address()));
1113 arguments->ShortPrint();
1114 PrintF("\n");
1115 }
1116 }
1117 }
1118 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001119}
1120
1121
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001122#ifdef ENABLE_DEBUGGER_SUPPORT
1123void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001124 Address parameters_top,
1125 uint32_t parameters_size,
1126 Address expressions_top,
1127 uint32_t expressions_size,
1128 DeoptimizedFrameInfo* info) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001129 ASSERT_EQ(DEBUGGER, bailout_type_);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001130 Address parameters_bottom = parameters_top + parameters_size;
1131 Address expressions_bottom = expressions_top + expressions_size;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001132 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
1133 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
1134
1135 // Check of the heap number to materialize actually belong to the frame
1136 // being extracted.
1137 Address slot = d.slot_address();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001138 if (parameters_top <= slot && slot < parameters_bottom) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001139 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001140
1141 int index = (info->parameters_count() - 1) -
1142 static_cast<int>(slot - parameters_top) / kPointerSize;
1143
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001144 if (trace_) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001145 PrintF("Materializing a new heap number %p [%e] in slot %p"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001146 "for parameter slot #%d\n",
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001147 reinterpret_cast<void*>(*num),
1148 d.value(),
1149 d.slot_address(),
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001150 index);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001151 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001152
1153 info->SetParameter(index, *num);
1154 } else if (expressions_top <= slot && slot < expressions_bottom) {
1155 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
1156
1157 int index = info->expression_count() - 1 -
1158 static_cast<int>(slot - expressions_top) / kPointerSize;
1159
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001160 if (trace_) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001161 PrintF("Materializing a new heap number %p [%e] in slot %p"
1162 "for expression slot #%d\n",
1163 reinterpret_cast<void*>(*num),
1164 d.value(),
1165 d.slot_address(),
1166 index);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001167 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001168
1169 info->SetExpression(index, *num);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001170 }
1171 }
1172}
1173#endif
1174
1175
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001176void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
1177 int frame_index,
1178 unsigned output_offset) {
1179 disasm::NameConverter converter;
1180 // A GC-safe temporary placeholder that we can put in the output frame.
1181 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
1182
1183 // Ignore commands marked as duplicate and act on the first non-duplicate.
1184 Translation::Opcode opcode =
1185 static_cast<Translation::Opcode>(iterator->Next());
1186 while (opcode == Translation::DUPLICATE) {
1187 opcode = static_cast<Translation::Opcode>(iterator->Next());
1188 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
1189 opcode = static_cast<Translation::Opcode>(iterator->Next());
1190 }
1191
1192 switch (opcode) {
1193 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001194 case Translation::JS_FRAME:
1195 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00001196 case Translation::CONSTRUCT_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001197 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001198 case Translation::SETTER_STUB_FRAME:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001199 case Translation::COMPILED_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001200 case Translation::DUPLICATE:
1201 UNREACHABLE();
1202 return;
1203
1204 case Translation::REGISTER: {
1205 int input_reg = iterator->Next();
1206 intptr_t input_value = input_->GetRegister(input_reg);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001207 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001208 PrintF(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001209 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001210 output_[frame_index]->GetTop() + output_offset,
1211 output_offset,
1212 input_value,
1213 converter.NameOfCPURegister(input_reg));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001214 reinterpret_cast<Object*>(input_value)->ShortPrint();
1215 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001216 }
1217 output_[frame_index]->SetFrameSlot(output_offset, input_value);
1218 return;
1219 }
1220
1221 case Translation::INT32_REGISTER: {
1222 int input_reg = iterator->Next();
1223 intptr_t value = input_->GetRegister(input_reg);
1224 bool is_smi = Smi::IsValid(value);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001225 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001226 PrintF(
1227 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
1228 output_[frame_index]->GetTop() + output_offset,
1229 output_offset,
1230 value,
1231 converter.NameOfCPURegister(input_reg),
1232 is_smi ? "smi" : "heap number");
1233 }
1234 if (is_smi) {
1235 intptr_t tagged_value =
1236 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1237 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
1238 } else {
1239 // We save the untagged value on the side and store a GC-safe
1240 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001241 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
1242 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001243 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
1244 }
1245 return;
1246 }
1247
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001248 case Translation::UINT32_REGISTER: {
1249 int input_reg = iterator->Next();
1250 uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
1251 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001252 if (trace_) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001253 PrintF(
1254 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
1255 " ; uint %s (%s)\n",
1256 output_[frame_index]->GetTop() + output_offset,
1257 output_offset,
1258 value,
1259 converter.NameOfCPURegister(input_reg),
1260 is_smi ? "smi" : "heap number");
1261 }
1262 if (is_smi) {
1263 intptr_t tagged_value =
1264 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1265 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
1266 } else {
1267 // We save the untagged value on the side and store a GC-safe
1268 // temporary placeholder in the frame.
1269 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
1270 static_cast<double>(static_cast<uint32_t>(value)));
1271 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
1272 }
1273 return;
1274 }
1275
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001276 case Translation::DOUBLE_REGISTER: {
1277 int input_reg = iterator->Next();
1278 double value = input_->GetDoubleRegister(input_reg);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001279 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001280 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
1281 output_[frame_index]->GetTop() + output_offset,
1282 output_offset,
1283 value,
1284 DoubleRegister::AllocationIndexToString(input_reg));
1285 }
1286 // We save the untagged value on the side and store a GC-safe
1287 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001288 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001289 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
1290 return;
1291 }
1292
1293 case Translation::STACK_SLOT: {
1294 int input_slot_index = iterator->Next();
1295 unsigned input_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001296 input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001297 intptr_t input_value = input_->GetFrameSlot(input_offset);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001298 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001299 PrintF(" 0x%08" V8PRIxPTR ": ",
1300 output_[frame_index]->GetTop() + output_offset);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001301 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001302 output_offset,
1303 input_value,
1304 input_offset);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 reinterpret_cast<Object*>(input_value)->ShortPrint();
1306 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001307 }
1308 output_[frame_index]->SetFrameSlot(output_offset, input_value);
1309 return;
1310 }
1311
1312 case Translation::INT32_STACK_SLOT: {
1313 int input_slot_index = iterator->Next();
1314 unsigned input_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001315 input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001316 intptr_t value = input_->GetFrameSlot(input_offset);
1317 bool is_smi = Smi::IsValid(value);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001318 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001319 PrintF(" 0x%08" V8PRIxPTR ": ",
1320 output_[frame_index]->GetTop() + output_offset);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001321 PrintF("[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001322 output_offset,
1323 value,
1324 input_offset,
1325 is_smi ? "smi" : "heap number");
1326 }
1327 if (is_smi) {
1328 intptr_t tagged_value =
1329 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1330 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
1331 } else {
1332 // We save the untagged value on the side and store a GC-safe
1333 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001334 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
1335 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001336 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
1337 }
1338 return;
1339 }
1340
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001341 case Translation::UINT32_STACK_SLOT: {
1342 int input_slot_index = iterator->Next();
1343 unsigned input_offset =
1344 input_->GetOffsetFromSlotIndex(input_slot_index);
1345 uintptr_t value =
1346 static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
1347 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001348 if (trace_) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001349 PrintF(" 0x%08" V8PRIxPTR ": ",
1350 output_[frame_index]->GetTop() + output_offset);
1351 PrintF("[top + %d] <- %" V8PRIuPTR " ; [sp + %d] (uint32 %s)\n",
1352 output_offset,
1353 value,
1354 input_offset,
1355 is_smi ? "smi" : "heap number");
1356 }
1357 if (is_smi) {
1358 intptr_t tagged_value =
1359 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1360 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
1361 } else {
1362 // We save the untagged value on the side and store a GC-safe
1363 // temporary placeholder in the frame.
1364 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
1365 static_cast<double>(static_cast<uint32_t>(value)));
1366 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
1367 }
1368 return;
1369 }
1370
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001371 case Translation::DOUBLE_STACK_SLOT: {
1372 int input_slot_index = iterator->Next();
1373 unsigned input_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001374 input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001375 double value = input_->GetDoubleFrameSlot(input_offset);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001376 if (trace_) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001377 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001378 output_[frame_index]->GetTop() + output_offset,
1379 output_offset,
1380 value,
1381 input_offset);
1382 }
1383 // We save the untagged value on the side and store a GC-safe
1384 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001385 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001386 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
1387 return;
1388 }
1389
1390 case Translation::LITERAL: {
1391 Object* literal = ComputeLiteral(iterator->Next());
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001392 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001393 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
1394 output_[frame_index]->GetTop() + output_offset,
1395 output_offset);
1396 literal->ShortPrint();
1397 PrintF(" ; literal\n");
1398 }
1399 intptr_t value = reinterpret_cast<intptr_t>(literal);
1400 output_[frame_index]->SetFrameSlot(output_offset, value);
1401 return;
1402 }
1403
1404 case Translation::ARGUMENTS_OBJECT: {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001405 bool args_known = iterator->Next();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001406 int args_index = iterator->Next() + 1; // Skip receiver.
1407 int args_length = iterator->Next() - 1; // Skip receiver.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001408 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001409 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
1410 output_[frame_index]->GetTop() + output_offset,
1411 output_offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 isolate_->heap()->arguments_marker()->ShortPrint();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001413 PrintF(" ; %sarguments object\n", args_known ? "" : "dummy ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001414 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001415 // Use the arguments marker value as a sentinel and fill in the arguments
1416 // object after the deoptimized frame is built.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001417 intptr_t value = reinterpret_cast<intptr_t>(
1418 isolate_->heap()->arguments_marker());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001419 AddArgumentsObject(
1420 output_[frame_index]->GetTop() + output_offset, args_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001421 output_[frame_index]->SetFrameSlot(output_offset, value);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001422 // We save the tagged argument values on the side and materialize the
1423 // actual arguments object after the deoptimized frame is built.
1424 for (int i = 0; i < args_length; i++) {
1425 unsigned input_offset = input_->GetOffsetFromSlotIndex(args_index + i);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001426 intptr_t input_value = args_known
1427 ? input_->GetFrameSlot(input_offset)
1428 : reinterpret_cast<intptr_t>(isolate_->heap()->the_hole_value());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001429 AddArgumentsObjectValue(input_value);
1430 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001431 return;
1432 }
1433 }
1434}
1435
1436
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001437static bool ObjectToInt32(Object* obj, int32_t* value) {
1438 if (obj->IsSmi()) {
1439 *value = Smi::cast(obj)->value();
1440 return true;
1441 }
1442
1443 if (obj->IsHeapNumber()) {
1444 double num = HeapNumber::cast(obj)->value();
1445 if (FastI2D(FastD2I(num)) != num) {
1446 if (FLAG_trace_osr) {
1447 PrintF("**** %g could not be converted to int32 ****\n",
1448 HeapNumber::cast(obj)->value());
1449 }
1450 return false;
1451 }
1452
1453 *value = FastD2I(num);
1454 return true;
1455 }
1456
1457 return false;
1458}
1459
1460
1461static bool ObjectToUint32(Object* obj, uint32_t* value) {
1462 if (obj->IsSmi()) {
1463 if (Smi::cast(obj)->value() < 0) return false;
1464
1465 *value = static_cast<uint32_t>(Smi::cast(obj)->value());
1466 return true;
1467 }
1468
1469 if (obj->IsHeapNumber()) {
1470 double num = HeapNumber::cast(obj)->value();
1471 if ((num < 0) || (FastUI2D(FastD2UI(num)) != num)) {
1472 if (FLAG_trace_osr) {
1473 PrintF("**** %g could not be converted to uint32 ****\n",
1474 HeapNumber::cast(obj)->value());
1475 }
1476 return false;
1477 }
1478
1479 *value = FastD2UI(num);
1480 return true;
1481 }
1482
1483 return false;
1484}
1485
1486
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001487bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
1488 int* input_offset) {
1489 disasm::NameConverter converter;
1490 FrameDescription* output = output_[0];
1491
1492 // The input values are all part of the unoptimized frame so they
1493 // are all tagged pointers.
1494 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
1495 Object* input_object = reinterpret_cast<Object*>(input_value);
1496
1497 Translation::Opcode opcode =
1498 static_cast<Translation::Opcode>(iterator->Next());
1499 bool duplicate = (opcode == Translation::DUPLICATE);
1500 if (duplicate) {
1501 opcode = static_cast<Translation::Opcode>(iterator->Next());
1502 }
1503
1504 switch (opcode) {
1505 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001506 case Translation::JS_FRAME:
1507 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00001508 case Translation::CONSTRUCT_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001509 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001510 case Translation::SETTER_STUB_FRAME:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001511 case Translation::COMPILED_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001512 case Translation::DUPLICATE:
1513 UNREACHABLE(); // Malformed input.
1514 return false;
1515
1516 case Translation::REGISTER: {
1517 int output_reg = iterator->Next();
1518 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001519 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001520 converter.NameOfCPURegister(output_reg),
1521 input_value,
1522 *input_offset);
1523 }
1524 output->SetRegister(output_reg, input_value);
1525 break;
1526 }
1527
1528 case Translation::INT32_REGISTER: {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001529 int32_t int32_value = 0;
1530 if (!ObjectToInt32(input_object, &int32_value)) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001531
1532 int output_reg = iterator->Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001533 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001534 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001535 converter.NameOfCPURegister(output_reg),
1536 int32_value,
1537 *input_offset);
1538 }
1539 output->SetRegister(output_reg, int32_value);
1540 break;
1541 }
1542
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001543 case Translation::UINT32_REGISTER: {
1544 uint32_t uint32_value = 0;
1545 if (!ObjectToUint32(input_object, &uint32_value)) return false;
1546
1547 int output_reg = iterator->Next();
1548 if (FLAG_trace_osr) {
1549 PrintF(" %s <- %u (uint32) ; [sp + %d]\n",
1550 converter.NameOfCPURegister(output_reg),
1551 uint32_value,
1552 *input_offset);
1553 }
1554 output->SetRegister(output_reg, static_cast<int32_t>(uint32_value));
1555 }
1556
1557
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001558 case Translation::DOUBLE_REGISTER: {
1559 // Abort OSR if we don't have a number.
1560 if (!input_object->IsNumber()) return false;
1561
1562 int output_reg = iterator->Next();
1563 double double_value = input_object->Number();
1564 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001565 PrintF(" %s <- %g (double) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001566 DoubleRegister::AllocationIndexToString(output_reg),
1567 double_value,
1568 *input_offset);
1569 }
1570 output->SetDoubleRegister(output_reg, double_value);
1571 break;
1572 }
1573
1574 case Translation::STACK_SLOT: {
1575 int output_index = iterator->Next();
1576 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001577 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001578 if (FLAG_trace_osr) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001579 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001580 output_offset,
1581 input_value,
1582 *input_offset);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001583 reinterpret_cast<Object*>(input_value)->ShortPrint();
1584 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001585 }
1586 output->SetFrameSlot(output_offset, input_value);
1587 break;
1588 }
1589
1590 case Translation::INT32_STACK_SLOT: {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001591 int32_t int32_value = 0;
1592 if (!ObjectToInt32(input_object, &int32_value)) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001593
1594 int output_index = iterator->Next();
1595 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001596 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001597 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001598 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599 output_offset,
1600 int32_value,
1601 *input_offset);
1602 }
1603 output->SetFrameSlot(output_offset, int32_value);
1604 break;
1605 }
1606
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001607 case Translation::UINT32_STACK_SLOT: {
1608 uint32_t uint32_value = 0;
1609 if (!ObjectToUint32(input_object, &uint32_value)) return false;
1610
1611 int output_index = iterator->Next();
1612 unsigned output_offset =
1613 output->GetOffsetFromSlotIndex(output_index);
1614 if (FLAG_trace_osr) {
1615 PrintF(" [sp + %d] <- %u (uint32) ; [sp + %d]\n",
1616 output_offset,
1617 uint32_value,
1618 *input_offset);
1619 }
1620 output->SetFrameSlot(output_offset, static_cast<int32_t>(uint32_value));
1621 break;
1622 }
1623
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001624 case Translation::DOUBLE_STACK_SLOT: {
1625 static const int kLowerOffset = 0 * kPointerSize;
1626 static const int kUpperOffset = 1 * kPointerSize;
1627
1628 // Abort OSR if we don't have a number.
1629 if (!input_object->IsNumber()) return false;
1630
1631 int output_index = iterator->Next();
1632 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001633 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001634 double double_value = input_object->Number();
1635 uint64_t int_value = BitCast<uint64_t, double>(double_value);
1636 int32_t lower = static_cast<int32_t>(int_value);
1637 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
1638 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001639 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001640 output_offset + kUpperOffset,
1641 upper,
1642 double_value,
1643 *input_offset);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001644 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001645 output_offset + kLowerOffset,
1646 lower,
1647 double_value,
1648 *input_offset);
1649 }
1650 output->SetFrameSlot(output_offset + kLowerOffset, lower);
1651 output->SetFrameSlot(output_offset + kUpperOffset, upper);
1652 break;
1653 }
1654
1655 case Translation::LITERAL: {
1656 // Just ignore non-materialized literals.
1657 iterator->Next();
1658 break;
1659 }
1660
1661 case Translation::ARGUMENTS_OBJECT: {
1662 // Optimized code assumes that the argument object has not been
1663 // materialized and so bypasses it when doing arguments access.
1664 // We should have bailed out before starting the frame
1665 // translation.
1666 UNREACHABLE();
1667 return false;
1668 }
1669 }
1670
1671 if (!duplicate) *input_offset -= kPointerSize;
1672 return true;
1673}
1674
1675
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001676void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
1677 Code* check_code,
1678 Code* replacement_code) {
1679 // Iterate over the stack check table and patch every stack check
1680 // call to an unconditional call to the replacement code.
1681 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1682 Address stack_check_cursor = unoptimized_code->instruction_start() +
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001683 unoptimized_code->stack_check_table_offset();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001684 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1685 stack_check_cursor += kIntSize;
1686 for (uint32_t i = 0; i < table_length; ++i) {
1687 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1688 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001689 PatchStackCheckCodeAt(unoptimized_code,
1690 pc_after,
1691 check_code,
1692 replacement_code);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001693 stack_check_cursor += 2 * kIntSize;
1694 }
1695}
1696
1697
1698void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
1699 Code* check_code,
1700 Code* replacement_code) {
1701 // Iterate over the stack check table and revert the patched
1702 // stack check calls.
1703 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
1704 Address stack_check_cursor = unoptimized_code->instruction_start() +
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001705 unoptimized_code->stack_check_table_offset();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001706 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
1707 stack_check_cursor += kIntSize;
1708 for (uint32_t i = 0; i < table_length; ++i) {
1709 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
1710 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001711 RevertStackCheckCodeAt(unoptimized_code,
1712 pc_after,
1713 check_code,
1714 replacement_code);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001715 stack_check_cursor += 2 * kIntSize;
1716 }
1717}
1718
1719
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001720unsigned Deoptimizer::ComputeInputFrameSize() const {
1721 unsigned fixed_size = ComputeFixedSize(function_);
1722 // The fp-to-sp delta already takes the context and the function
1723 // into account so we have to avoid double counting them (-2).
1724 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
1725#ifdef DEBUG
1726 if (bailout_type_ == OSR) {
1727 // TODO(kasperl): It would be nice if we could verify that the
1728 // size matches with the stack height we can compute based on the
1729 // environment at the OSR entry. The code for that his built into
1730 // the DoComputeOsrOutputFrame function for now.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001731 } else if (compiled_code_->kind() != Code::COMPILED_STUB) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001732 unsigned stack_slots = compiled_code_->stack_slots();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001733 unsigned outgoing_size = ComputeOutgoingArgumentSize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001734 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
1735 }
1736#endif
1737 return result;
1738}
1739
1740
1741unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
1742 // The fixed part of the frame consists of the return address, frame
1743 // pointer, function, context, and all the incoming arguments.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001744 return ComputeIncomingArgumentSize(function) +
1745 StandardFrameConstants::kFixedFrameSize;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001746}
1747
1748
1749unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
1750 // The incoming arguments is the values for formal parameters and
1751 // the receiver. Every slot contains a pointer.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001752 if (function->IsSmi()) {
1753 ASSERT(Smi::cast(function) == Smi::FromInt(StackFrame::STUB));
1754 return 0;
1755 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001756 unsigned arguments = function->shared()->formal_parameter_count() + 1;
1757 return arguments * kPointerSize;
1758}
1759
1760
1761unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
1762 DeoptimizationInputData* data = DeoptimizationInputData::cast(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001763 compiled_code_->deoptimization_data());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001764 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
1765 return height * kPointerSize;
1766}
1767
1768
1769Object* Deoptimizer::ComputeLiteral(int index) const {
1770 DeoptimizationInputData* data = DeoptimizationInputData::cast(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001771 compiled_code_->deoptimization_data());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001772 FixedArray* literals = data->LiteralArray();
1773 return literals->get(index);
1774}
1775
1776
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001777void Deoptimizer::AddArgumentsObject(intptr_t slot_address, int argc) {
1778 ArgumentsObjectMaterializationDescriptor object_desc(
1779 reinterpret_cast<Address>(slot_address), argc);
1780 deferred_arguments_objects_.Add(object_desc);
1781}
1782
1783
1784void Deoptimizer::AddArgumentsObjectValue(intptr_t value) {
1785 deferred_arguments_objects_values_.Add(reinterpret_cast<Object*>(value));
1786}
1787
1788
1789void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001790 HeapNumberMaterializationDescriptor value_desc(
1791 reinterpret_cast<Address>(slot_address), value);
1792 deferred_heap_numbers_.Add(value_desc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001793}
1794
1795
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001796void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
1797 BailoutType type,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001798 int max_entry_id) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001799 // We cannot run this if the serializer is enabled because this will
1800 // cause us to emit relocation information for the external
1801 // references. This is fine because the deoptimizer's code section
1802 // isn't meant to be serialized at all.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001803 ASSERT(type == EAGER || type == LAZY);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001804 DeoptimizerData* data = isolate->deoptimizer_data();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001805 int entry_count = (type == EAGER)
1806 ? data->eager_deoptimization_entry_code_entries_
1807 : data->lazy_deoptimization_entry_code_entries_;
1808 if (max_entry_id < entry_count) return;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001809 entry_count = Max(entry_count, Deoptimizer::kMinNumberOfEntries);
1810 while (max_entry_id >= entry_count) entry_count *= 2;
1811 ASSERT(entry_count <= Deoptimizer::kMaxNumberOfEntries);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001812
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001813 MacroAssembler masm(isolate, NULL, 16 * KB);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001814 masm.set_emit_debug_code(false);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001815 GenerateDeoptimizationEntries(&masm, entry_count, type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001816 CodeDesc desc;
1817 masm.GetCode(&desc);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00001818 ASSERT(!RelocInfo::RequiresRelocation(desc));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001819
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001820 MemoryChunk* chunk = type == EAGER
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001821 ? data->eager_deoptimization_entry_code_
1822 : data->lazy_deoptimization_entry_code_;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001823 ASSERT(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
1824 desc.instr_size);
1825 chunk->CommitArea(desc.instr_size);
1826 memcpy(chunk->area_start(), desc.buffer, desc.instr_size);
1827 CPU::FlushICache(chunk->area_start(), desc.instr_size);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001828
1829 if (type == EAGER) {
1830 data->eager_deoptimization_entry_code_entries_ = entry_count;
1831 } else {
1832 data->lazy_deoptimization_entry_code_entries_ = entry_count;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001833 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001834}
1835
1836
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001837void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function,
1838 Code* code) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001839 SharedFunctionInfo* shared = function->shared();
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001840 Object* undefined = Isolate::Current()->heap()->undefined_value();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001841 Object* current = function;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001842
1843 while (current != undefined) {
1844 JSFunction* func = JSFunction::cast(current);
1845 current = func->next_function_link();
1846 func->set_code(shared->code());
1847 func->set_next_function_link(undefined);
1848 }
1849}
1850
1851
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001852FrameDescription::FrameDescription(uint32_t frame_size,
1853 JSFunction* function)
1854 : frame_size_(frame_size),
1855 function_(function),
1856 top_(kZapUint32),
1857 pc_(kZapUint32),
ulan@chromium.org967e2702012-02-28 09:49:15 +00001858 fp_(kZapUint32),
1859 context_(kZapUint32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001860 // Zap all the registers.
1861 for (int r = 0; r < Register::kNumRegisters; r++) {
1862 SetRegister(r, kZapUint32);
1863 }
1864
1865 // Zap all the slots.
1866 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
1867 SetFrameSlot(o, kZapUint32);
1868 }
1869}
1870
1871
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001872int FrameDescription::ComputeFixedSize() {
1873 return StandardFrameConstants::kFixedFrameSize +
1874 (ComputeParametersCount() + 1) * kPointerSize;
1875}
1876
1877
1878unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001879 if (slot_index >= 0) {
1880 // Local or spill slots. Skip the fixed part of the frame
1881 // including all arguments.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001882 unsigned base = GetFrameSize() - ComputeFixedSize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001883 return base - ((slot_index + 1) * kPointerSize);
1884 } else {
1885 // Incoming parameter.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001886 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
1887 unsigned base = GetFrameSize() - arg_size;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001888 return base - ((slot_index + 1) * kPointerSize);
1889 }
1890}
1891
1892
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001893int FrameDescription::ComputeParametersCount() {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001894 switch (type_) {
1895 case StackFrame::JAVA_SCRIPT:
1896 return function_->shared()->formal_parameter_count();
1897 case StackFrame::ARGUMENTS_ADAPTOR: {
1898 // Last slot contains number of incomming arguments as a smi.
1899 // Can't use GetExpression(0) because it would cause infinite recursion.
1900 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value();
1901 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001902 case StackFrame::STUB:
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001903 return -1; // Minus receiver.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001904 default:
1905 UNREACHABLE();
1906 return 0;
1907 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001908}
1909
1910
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001911Object* FrameDescription::GetParameter(int index) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001912 ASSERT(index >= 0);
1913 ASSERT(index < ComputeParametersCount());
1914 // The slot indexes for incoming arguments are negative.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001915 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001916 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1917}
1918
1919
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001920unsigned FrameDescription::GetExpressionCount() {
1921 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1922 unsigned size = GetFrameSize() - ComputeFixedSize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001923 return size / kPointerSize;
1924}
1925
1926
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001927Object* FrameDescription::GetExpression(int index) {
1928 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
1929 unsigned offset = GetOffsetFromSlotIndex(index);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001930 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1931}
1932
1933
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001934void TranslationBuffer::Add(int32_t value, Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001935 // Encode the sign bit in the least significant bit.
1936 bool is_negative = (value < 0);
1937 uint32_t bits = ((is_negative ? -value : value) << 1) |
1938 static_cast<int32_t>(is_negative);
1939 // Encode the individual bytes using the least significant bit of
1940 // each byte to indicate whether or not more bytes follow.
1941 do {
1942 uint32_t next = bits >> 7;
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001943 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001944 bits = next;
1945 } while (bits != 0);
1946}
1947
1948
1949int32_t TranslationIterator::Next() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001950 // Run through the bytes until we reach one with a least significant
1951 // bit of zero (marks the end).
1952 uint32_t bits = 0;
1953 for (int i = 0; true; i += 7) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001954 ASSERT(HasNext());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001955 uint8_t next = buffer_->get(index_++);
1956 bits |= (next >> 1) << i;
1957 if ((next & 1) == 0) break;
1958 }
1959 // The bits encode the sign in the least significant bit.
1960 bool is_negative = (bits & 1) == 1;
1961 int32_t result = bits >> 1;
1962 return is_negative ? -result : result;
1963}
1964
1965
1966Handle<ByteArray> TranslationBuffer::CreateByteArray() {
1967 int length = contents_.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001968 Handle<ByteArray> result =
1969 Isolate::Current()->factory()->NewByteArray(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001970 memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
1971 return result;
1972}
1973
1974
ulan@chromium.org967e2702012-02-28 09:49:15 +00001975void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001976 buffer_->Add(CONSTRUCT_STUB_FRAME, zone());
1977 buffer_->Add(literal_id, zone());
1978 buffer_->Add(height, zone());
ulan@chromium.org967e2702012-02-28 09:49:15 +00001979}
1980
1981
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001982void Translation::BeginGetterStubFrame(int literal_id) {
1983 buffer_->Add(GETTER_STUB_FRAME, zone());
1984 buffer_->Add(literal_id, zone());
1985}
1986
1987
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001988void Translation::BeginSetterStubFrame(int literal_id) {
1989 buffer_->Add(SETTER_STUB_FRAME, zone());
1990 buffer_->Add(literal_id, zone());
1991}
1992
1993
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001994void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001995 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone());
1996 buffer_->Add(literal_id, zone());
1997 buffer_->Add(height, zone());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001998}
1999
2000
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002001void Translation::BeginJSFrame(BailoutId node_id,
2002 int literal_id,
2003 unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002004 buffer_->Add(JS_FRAME, zone());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002005 buffer_->Add(node_id.ToInt(), zone());
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002006 buffer_->Add(literal_id, zone());
2007 buffer_->Add(height, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008}
2009
2010
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002011void Translation::BeginCompiledStubFrame() {
2012 buffer_->Add(COMPILED_STUB_FRAME, zone());
2013}
2014
2015
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002016void Translation::StoreRegister(Register reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002017 buffer_->Add(REGISTER, zone());
2018 buffer_->Add(reg.code(), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002019}
2020
2021
2022void Translation::StoreInt32Register(Register reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002023 buffer_->Add(INT32_REGISTER, zone());
2024 buffer_->Add(reg.code(), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002025}
2026
2027
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002028void Translation::StoreUint32Register(Register reg) {
2029 buffer_->Add(UINT32_REGISTER, zone());
2030 buffer_->Add(reg.code(), zone());
2031}
2032
2033
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002034void Translation::StoreDoubleRegister(DoubleRegister reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002035 buffer_->Add(DOUBLE_REGISTER, zone());
2036 buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002037}
2038
2039
2040void Translation::StoreStackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002041 buffer_->Add(STACK_SLOT, zone());
2042 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002043}
2044
2045
2046void Translation::StoreInt32StackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002047 buffer_->Add(INT32_STACK_SLOT, zone());
2048 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002049}
2050
2051
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002052void Translation::StoreUint32StackSlot(int index) {
2053 buffer_->Add(UINT32_STACK_SLOT, zone());
2054 buffer_->Add(index, zone());
2055}
2056
2057
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002058void Translation::StoreDoubleStackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002059 buffer_->Add(DOUBLE_STACK_SLOT, zone());
2060 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002061}
2062
2063
2064void Translation::StoreLiteral(int literal_id) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002065 buffer_->Add(LITERAL, zone());
2066 buffer_->Add(literal_id, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002067}
2068
2069
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002070void Translation::StoreArgumentsObject(bool args_known,
2071 int args_index,
2072 int args_length) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002073 buffer_->Add(ARGUMENTS_OBJECT, zone());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002074 buffer_->Add(args_known, zone());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002075 buffer_->Add(args_index, zone());
2076 buffer_->Add(args_length, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002077}
2078
2079
2080void Translation::MarkDuplicate() {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002081 buffer_->Add(DUPLICATE, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002082}
2083
2084
2085int Translation::NumberOfOperandsFor(Opcode opcode) {
2086 switch (opcode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002087 case DUPLICATE:
2088 return 0;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002089 case GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002090 case SETTER_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002091 case REGISTER:
2092 case INT32_REGISTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002093 case UINT32_REGISTER:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002094 case DOUBLE_REGISTER:
2095 case STACK_SLOT:
2096 case INT32_STACK_SLOT:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002097 case UINT32_STACK_SLOT:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002098 case DOUBLE_STACK_SLOT:
2099 case LITERAL:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002100 case COMPILED_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002101 return 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002102 case BEGIN:
2103 case ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00002104 case CONSTRUCT_STUB_FRAME:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002105 return 2;
2106 case JS_FRAME:
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002107 case ARGUMENTS_OBJECT:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002108 return 3;
2109 }
2110 UNREACHABLE();
2111 return -1;
2112}
2113
2114
whesse@chromium.org7b260152011-06-20 15:33:18 +00002115#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002116
2117const char* Translation::StringFor(Opcode opcode) {
2118 switch (opcode) {
2119 case BEGIN:
2120 return "BEGIN";
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002121 case JS_FRAME:
2122 return "JS_FRAME";
2123 case ARGUMENTS_ADAPTOR_FRAME:
2124 return "ARGUMENTS_ADAPTOR_FRAME";
ulan@chromium.org967e2702012-02-28 09:49:15 +00002125 case CONSTRUCT_STUB_FRAME:
2126 return "CONSTRUCT_STUB_FRAME";
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002127 case GETTER_STUB_FRAME:
2128 return "GETTER_STUB_FRAME";
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002129 case SETTER_STUB_FRAME:
2130 return "SETTER_STUB_FRAME";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002131 case COMPILED_STUB_FRAME:
2132 return "COMPILED_STUB_FRAME";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002133 case REGISTER:
2134 return "REGISTER";
2135 case INT32_REGISTER:
2136 return "INT32_REGISTER";
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002137 case UINT32_REGISTER:
2138 return "UINT32_REGISTER";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002139 case DOUBLE_REGISTER:
2140 return "DOUBLE_REGISTER";
2141 case STACK_SLOT:
2142 return "STACK_SLOT";
2143 case INT32_STACK_SLOT:
2144 return "INT32_STACK_SLOT";
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002145 case UINT32_STACK_SLOT:
2146 return "UINT32_STACK_SLOT";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002147 case DOUBLE_STACK_SLOT:
2148 return "DOUBLE_STACK_SLOT";
2149 case LITERAL:
2150 return "LITERAL";
2151 case ARGUMENTS_OBJECT:
2152 return "ARGUMENTS_OBJECT";
2153 case DUPLICATE:
2154 return "DUPLICATE";
2155 }
2156 UNREACHABLE();
2157 return "";
2158}
2159
2160#endif
2161
2162
2163DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002164 GlobalHandles* global_handles = Isolate::Current()->global_handles();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002165 // Globalize the code object and make it weak.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002166 code_ = Handle<Code>::cast(global_handles->Create(code));
2167 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
2168 this,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002169 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002170 Deoptimizer::HandleWeakDeoptimizedCode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002171}
2172
2173
2174DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002175 GlobalHandles* global_handles = Isolate::Current()->global_handles();
2176 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002177}
2178
2179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002180// We can't intermix stack decoding and allocations because
2181// deoptimization infrastracture is not GC safe.
2182// Thus we build a temporary structure in malloced space.
2183SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
2184 DeoptimizationInputData* data,
2185 JavaScriptFrame* frame) {
2186 Translation::Opcode opcode =
2187 static_cast<Translation::Opcode>(iterator->Next());
2188
2189 switch (opcode) {
2190 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002191 case Translation::JS_FRAME:
2192 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00002193 case Translation::CONSTRUCT_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002194 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002195 case Translation::SETTER_STUB_FRAME:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002196 // Peeled off before getting here.
2197 break;
2198
2199 case Translation::ARGUMENTS_OBJECT:
2200 // This can be only emitted for local slots not for argument slots.
2201 break;
2202
2203 case Translation::REGISTER:
2204 case Translation::INT32_REGISTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002205 case Translation::UINT32_REGISTER:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002206 case Translation::DOUBLE_REGISTER:
2207 case Translation::DUPLICATE:
2208 // We are at safepoint which corresponds to call. All registers are
2209 // saved by caller so there would be no live registers at this
2210 // point. Thus these translation commands should not be used.
2211 break;
2212
2213 case Translation::STACK_SLOT: {
2214 int slot_index = iterator->Next();
2215 Address slot_addr = SlotAddress(frame, slot_index);
2216 return SlotRef(slot_addr, SlotRef::TAGGED);
2217 }
2218
2219 case Translation::INT32_STACK_SLOT: {
2220 int slot_index = iterator->Next();
2221 Address slot_addr = SlotAddress(frame, slot_index);
2222 return SlotRef(slot_addr, SlotRef::INT32);
2223 }
2224
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002225 case Translation::UINT32_STACK_SLOT: {
2226 int slot_index = iterator->Next();
2227 Address slot_addr = SlotAddress(frame, slot_index);
2228 return SlotRef(slot_addr, SlotRef::UINT32);
2229 }
2230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002231 case Translation::DOUBLE_STACK_SLOT: {
2232 int slot_index = iterator->Next();
2233 Address slot_addr = SlotAddress(frame, slot_index);
2234 return SlotRef(slot_addr, SlotRef::DOUBLE);
2235 }
2236
2237 case Translation::LITERAL: {
2238 int literal_index = iterator->Next();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002239 return SlotRef(data->GetIsolate(),
2240 data->LiteralArray()->get(literal_index));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002241 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002242
2243 case Translation::COMPILED_STUB_FRAME:
2244 UNREACHABLE();
2245 break;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002246 }
2247
2248 UNREACHABLE();
2249 return SlotRef();
2250}
2251
2252
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002253void SlotRef::ComputeSlotsForArguments(Vector<SlotRef>* args_slots,
2254 TranslationIterator* it,
2255 DeoptimizationInputData* data,
2256 JavaScriptFrame* frame) {
2257 // Process the translation commands for the arguments.
2258
2259 // Skip the translation command for the receiver.
2260 it->Skip(Translation::NumberOfOperandsFor(
2261 static_cast<Translation::Opcode>(it->Next())));
2262
2263 // Compute slots for arguments.
2264 for (int i = 0; i < args_slots->length(); ++i) {
2265 (*args_slots)[i] = ComputeSlotForNextArgument(it, data, frame);
2266 }
2267}
2268
2269
2270Vector<SlotRef> SlotRef::ComputeSlotMappingForArguments(
2271 JavaScriptFrame* frame,
2272 int inlined_jsframe_index,
2273 int formal_parameter_count) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002274 AssertNoAllocation no_gc;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002275 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002276 DeoptimizationInputData* data =
2277 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
2278 TranslationIterator it(data->TranslationByteArray(),
2279 data->TranslationIndex(deopt_index)->value());
2280 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
2281 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002282 it.Next(); // Drop frame count.
2283 int jsframe_count = it.Next();
2284 USE(jsframe_count);
2285 ASSERT(jsframe_count > inlined_jsframe_index);
2286 int jsframes_to_skip = inlined_jsframe_index;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002287 while (true) {
2288 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002289 if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) {
2290 if (jsframes_to_skip == 0) {
2291 ASSERT(Translation::NumberOfOperandsFor(opcode) == 2);
2292
2293 it.Skip(1); // literal id
2294 int height = it.Next();
2295
2296 // We reached the arguments adaptor frame corresponding to the
2297 // inlined function in question. Number of arguments is height - 1.
2298 Vector<SlotRef> args_slots =
2299 Vector<SlotRef>::New(height - 1); // Minus receiver.
2300 ComputeSlotsForArguments(&args_slots, &it, data, frame);
2301 return args_slots;
2302 }
2303 } else if (opcode == Translation::JS_FRAME) {
2304 if (jsframes_to_skip == 0) {
2305 // Skip over operands to advance to the next opcode.
2306 it.Skip(Translation::NumberOfOperandsFor(opcode));
2307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002308 // We reached the frame corresponding to the inlined function
2309 // in question. Process the translation commands for the
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002310 // arguments. Number of arguments is equal to the number of
2311 // format parameter count.
2312 Vector<SlotRef> args_slots =
2313 Vector<SlotRef>::New(formal_parameter_count);
2314 ComputeSlotsForArguments(&args_slots, &it, data, frame);
2315 return args_slots;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002316 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002317 jsframes_to_skip--;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002318 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002319
2320 // Skip over operands to advance to the next opcode.
2321 it.Skip(Translation::NumberOfOperandsFor(opcode));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002322 }
2323
2324 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002325 return Vector<SlotRef>();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002326}
2327
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002328#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002329
ulan@chromium.org967e2702012-02-28 09:49:15 +00002330DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
2331 int frame_index,
2332 bool has_arguments_adaptor,
2333 bool has_construct_stub) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002334 FrameDescription* output_frame = deoptimizer->output_[frame_index];
ulan@chromium.org967e2702012-02-28 09:49:15 +00002335 function_ = output_frame->GetFunction();
2336 has_construct_stub_ = has_construct_stub;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002337 expression_count_ = output_frame->GetExpressionCount();
2338 expression_stack_ = new Object*[expression_count_];
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002339 // Get the source position using the unoptimized code.
2340 Address pc = reinterpret_cast<Address>(output_frame->GetPc());
2341 Code* code = Code::cast(Isolate::Current()->heap()->FindCodeObject(pc));
2342 source_position_ = code->SourcePosition(pc);
2343
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002344 for (int i = 0; i < expression_count_; i++) {
2345 SetExpression(i, output_frame->GetExpression(i));
2346 }
2347
2348 if (has_arguments_adaptor) {
2349 output_frame = deoptimizer->output_[frame_index - 1];
2350 ASSERT(output_frame->GetFrameType() == StackFrame::ARGUMENTS_ADAPTOR);
2351 }
2352
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002353 parameters_count_ = output_frame->ComputeParametersCount();
2354 parameters_ = new Object*[parameters_count_];
2355 for (int i = 0; i < parameters_count_; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002356 SetParameter(i, output_frame->GetParameter(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002357 }
2358}
2359
2360
2361DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002362 delete[] expression_stack_;
2363 delete[] parameters_;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002364}
2365
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002366
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002367void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002368 v->VisitPointer(BitCast<Object**>(&function_));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002369 v->VisitPointers(parameters_, parameters_ + parameters_count_);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002370 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
2371}
2372
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002373#endif // ENABLE_DEBUGGER_SUPPORT
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002374
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002375} } // namespace v8::internal