blob: 14c1d730d01d6f7b5f8e27b314ec463a9d210443 [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
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000043static MemoryChunk* AllocateCodeChunk(MemoryAllocator* allocator) {
44 return allocator->AllocateChunk(Deoptimizer::GetMaxDeoptTableSize(),
45 OS::CommitPageSize(),
46 EXECUTABLE,
47 NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000048}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049
50
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000051DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator)
52 : allocator_(allocator),
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000053 current_(NULL),
54#ifdef ENABLE_DEBUGGER_SUPPORT
55 deoptimized_frame_info_(NULL),
56#endif
danno@chromium.orgaefd6072013-05-14 14:11:47 +000057 deoptimizing_code_list_(NULL) {
58 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
59 deopt_entry_code_entries_[i] = -1;
60 deopt_entry_code_[i] = AllocateCodeChunk(allocator);
61 }
62}
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000063
64
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065DeoptimizerData::~DeoptimizerData() {
danno@chromium.orgaefd6072013-05-14 14:11:47 +000066 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
67 allocator_->Free(deopt_entry_code_[i]);
68 deopt_entry_code_[i] = NULL;
69 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000070
danno@chromium.org72204d52012-10-31 10:02:10 +000071 DeoptimizingCodeListNode* current = deoptimizing_code_list_;
72 while (current != NULL) {
73 DeoptimizingCodeListNode* prev = current;
74 current = current->next();
75 delete prev;
76 }
77 deoptimizing_code_list_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000078}
79
ricow@chromium.org4f693d62011-07-04 14:01:31 +000080
81#ifdef ENABLE_DEBUGGER_SUPPORT
82void DeoptimizerData::Iterate(ObjectVisitor* v) {
83 if (deoptimized_frame_info_ != NULL) {
84 deoptimized_frame_info_->Iterate(v);
85 }
86}
87#endif
88
89
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000090Code* DeoptimizerData::FindDeoptimizingCode(Address addr) {
91 for (DeoptimizingCodeListNode* node = deoptimizing_code_list_;
92 node != NULL;
93 node = node->next()) {
94 if (node->code()->contains(addr)) return *node->code();
95 }
96 return NULL;
97}
98
99
100void DeoptimizerData::RemoveDeoptimizingCode(Code* code) {
101 for (DeoptimizingCodeListNode *prev = NULL, *cur = deoptimizing_code_list_;
102 cur != NULL;
103 prev = cur, cur = cur->next()) {
104 if (*cur->code() == code) {
105 if (prev == NULL) {
106 deoptimizing_code_list_ = cur->next();
107 } else {
108 prev->set_next(cur->next());
109 }
110 delete cur;
111 return;
112 }
113 }
114 // Deoptimizing code is removed through weak callback. Each object is expected
115 // to be removed once and only once.
116 UNREACHABLE();
117}
118
119
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000120// We rely on this function not causing a GC. It is called from generated code
121// without having a real stack frame in place.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000122Deoptimizer* Deoptimizer::New(JSFunction* function,
123 BailoutType type,
124 unsigned bailout_id,
125 Address from,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 int fp_to_sp_delta,
127 Isolate* isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000128 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
129 function,
130 type,
131 bailout_id,
132 from,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000133 fp_to_sp_delta,
134 NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 ASSERT(isolate->deoptimizer_data()->current_ == NULL);
136 isolate->deoptimizer_data()->current_ = deoptimizer;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000137 return deoptimizer;
138}
139
140
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000141// No larger than 2K on all platforms
142static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
143
144
145size_t Deoptimizer::GetMaxDeoptTableSize() {
146 int entries_size =
147 Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
148 int commit_page_size = static_cast<int>(OS::CommitPageSize());
149 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
150 commit_page_size) + 1;
151 return static_cast<size_t>(commit_page_size * page_count);
152}
153
154
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000155Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000156 Deoptimizer* result = isolate->deoptimizer_data()->current_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000157 ASSERT(result != NULL);
158 result->DeleteFrameDescriptions();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000159 isolate->deoptimizer_data()->current_ = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000160 return result;
161}
162
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000163
164int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) {
165 if (jsframe_index == 0) return 0;
166
167 int frame_index = 0;
168 while (jsframe_index >= 0) {
169 FrameDescription* frame = output_[frame_index];
170 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) {
171 jsframe_index--;
172 }
173 frame_index++;
174 }
175
176 return frame_index - 1;
177}
178
179
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000180#ifdef ENABLE_DEBUGGER_SUPPORT
181DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
182 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000183 int jsframe_index,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000184 Isolate* isolate) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000185 ASSERT(frame->is_optimized());
186 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
187
188 // Get the function and code from the frame.
189 JSFunction* function = JSFunction::cast(frame->function());
190 Code* code = frame->LookupCode();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000191
192 // Locate the deoptimization point in the code. As we are at a call the
193 // return address must be at a place in the code with deoptimization support.
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000194 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
195 int deoptimization_index = safepoint_entry.deoptimization_index();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000196 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
197
198 // Always use the actual stack slots when calculating the fp to sp
199 // delta adding two for the function and context.
200 unsigned stack_slots = code->stack_slots();
201 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
202
203 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
204 function,
205 Deoptimizer::DEBUGGER,
206 deoptimization_index,
207 frame->pc(),
208 fp_to_sp_delta,
209 code);
210 Address tos = frame->fp() - fp_to_sp_delta;
211 deoptimizer->FillInputFrame(tos, frame);
212
213 // Calculate the output frames.
214 Deoptimizer::ComputeOutputFrames(deoptimizer);
215
216 // Create the GC safe output frame information and register it for GC
217 // handling.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000218 ASSERT_LT(jsframe_index, deoptimizer->jsframe_count());
219
220 // Convert JS frame index into frame index.
221 int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index);
222
223 bool has_arguments_adaptor =
224 frame_index > 0 &&
225 deoptimizer->output_[frame_index - 1]->GetFrameType() ==
226 StackFrame::ARGUMENTS_ADAPTOR;
227
ulan@chromium.org967e2702012-02-28 09:49:15 +0000228 int construct_offset = has_arguments_adaptor ? 2 : 1;
229 bool has_construct_stub =
230 frame_index >= construct_offset &&
231 deoptimizer->output_[frame_index - construct_offset]->GetFrameType() ==
232 StackFrame::CONSTRUCT;
233
234 DeoptimizedFrameInfo* info = new DeoptimizedFrameInfo(deoptimizer,
235 frame_index,
236 has_arguments_adaptor,
237 has_construct_stub);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000238 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
239
240 // Get the "simulated" top and size for the requested frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000241 FrameDescription* parameters_frame =
242 deoptimizer->output_[
243 has_arguments_adaptor ? (frame_index - 1) : frame_index];
244
245 uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize;
246 Address parameters_top = reinterpret_cast<Address>(
247 parameters_frame->GetTop() + (parameters_frame->GetFrameSize() -
248 parameters_size));
249
250 uint32_t expressions_size = info->expression_count() * kPointerSize;
251 Address expressions_top = reinterpret_cast<Address>(
252 deoptimizer->output_[frame_index]->GetTop());
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000253
254 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
255 deoptimizer->DeleteFrameDescriptions();
256
257 // Allocate a heap number for the doubles belonging to this frame.
258 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000259 parameters_top, parameters_size, expressions_top, expressions_size, info);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000260
261 // Finished using the deoptimizer instance.
262 delete deoptimizer;
263
264 return info;
265}
266
267
268void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
269 Isolate* isolate) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000270 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
271 delete info;
272 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
273}
274#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000275
276void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
277 int count,
278 BailoutType type) {
279 TableEntryGenerator generator(masm, type, count);
280 generator.Generate();
281}
282
283
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000284void Deoptimizer::VisitAllOptimizedFunctionsForContext(
285 Context* context, OptimizedFunctionVisitor* visitor) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000286 Isolate* isolate = context->GetIsolate();
287 ZoneScope zone_scope(isolate->runtime_zone(), DELETE_ON_EXIT);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000288 DisallowHeapAllocation no_allocation;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000289
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000290 ASSERT(context->IsNativeContext());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000291
292 visitor->EnterContext(context);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000293
294 // Create a snapshot of the optimized functions list. This is needed because
295 // visitors might remove more than one link from the list at once.
296 ZoneList<JSFunction*> snapshot(1, isolate->runtime_zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000297 Object* element = context->OptimizedFunctionsListHead();
298 while (!element->IsUndefined()) {
299 JSFunction* element_function = JSFunction::cast(element);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000300 snapshot.Add(element_function, isolate->runtime_zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000301 element = element_function->next_function_link();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000302 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000303
304 // Run through the snapshot of optimized functions and visit them.
305 for (int i = 0; i < snapshot.length(); ++i) {
306 visitor->VisitFunction(snapshot.at(i));
307 }
308
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 visitor->LeaveContext(context);
310}
311
312
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000313void Deoptimizer::VisitAllOptimizedFunctions(
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000314 Isolate* isolate,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000315 OptimizedFunctionVisitor* visitor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000316 DisallowHeapAllocation no_allocation;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000317
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000318 // Run through the list of all native contexts and deoptimize.
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000319 Object* context = isolate->heap()->native_contexts_list();
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000320 while (!context->IsUndefined()) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000321 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000322 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000323 }
324}
325
326
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000327// Removes the functions selected by the given filter from the optimized
328// function list of the given context and partitions the removed functions
329// into one or more lists such that all functions in a list share the same
330// code. The head of each list is written in the deoptimizing_functions field
331// of the corresponding code object.
332// The found code objects are returned in the given zone list.
333static void PartitionOptimizedFunctions(Context* context,
334 OptimizedFunctionFilter* filter,
335 ZoneList<Code*>* partitions,
336 Zone* zone,
337 Object* undefined) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000338 DisallowHeapAllocation no_allocation;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000339 Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST);
340 Object* remainder_head = undefined;
341 Object* remainder_tail = undefined;
342 ASSERT_EQ(0, partitions->length());
343 while (current != undefined) {
344 JSFunction* function = JSFunction::cast(current);
345 current = function->next_function_link();
346 if (filter->TakeFunction(function)) {
347 Code* code = function->code();
348 if (code->deoptimizing_functions() == undefined) {
349 partitions->Add(code, zone);
350 } else {
351 ASSERT(partitions->Contains(code));
352 }
353 function->set_next_function_link(code->deoptimizing_functions());
354 code->set_deoptimizing_functions(function);
355 } else {
356 if (remainder_head == undefined) {
357 remainder_head = function;
358 } else {
359 JSFunction::cast(remainder_tail)->set_next_function_link(function);
360 }
361 remainder_tail = function;
362 }
363 }
364 if (remainder_tail != undefined) {
365 JSFunction::cast(remainder_tail)->set_next_function_link(undefined);
366 }
367 context->set(Context::OPTIMIZED_FUNCTIONS_LIST, remainder_head);
368}
369
370
371class DeoptimizeAllFilter : public OptimizedFunctionFilter {
372 public:
373 virtual bool TakeFunction(JSFunction* function) {
374 return true;
375 }
376};
377
378
379class DeoptimizeWithMatchingCodeFilter : public OptimizedFunctionFilter {
380 public:
381 explicit DeoptimizeWithMatchingCodeFilter(Code* code) : code_(code) {}
382 virtual bool TakeFunction(JSFunction* function) {
383 return function->code() == code_;
384 }
385 private:
386 Code* code_;
387};
388
389
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000390void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000391 DisallowHeapAllocation no_allocation;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000392
393 if (FLAG_trace_deopt) {
394 PrintF("[deoptimize all contexts]\n");
395 }
396
397 DeoptimizeAllFilter filter;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000398 DeoptimizeAllFunctionsWith(isolate, &filter);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000399}
400
401
402void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000403 DisallowHeapAllocation no_allocation;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000404 DeoptimizeAllFilter filter;
405 if (object->IsJSGlobalProxy()) {
406 Object* proto = object->GetPrototype();
407 ASSERT(proto->IsJSGlobalObject());
408 DeoptimizeAllFunctionsForContext(
409 GlobalObject::cast(proto)->native_context(), &filter);
410 } else if (object->IsGlobalObject()) {
411 DeoptimizeAllFunctionsForContext(
412 GlobalObject::cast(object)->native_context(), &filter);
413 }
414}
415
416
417void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
418 if (!function->IsOptimized()) return;
419 Code* code = function->code();
420 Context* context = function->context()->native_context();
421 Isolate* isolate = context->GetIsolate();
422 Object* undefined = isolate->heap()->undefined_value();
423 Zone* zone = isolate->runtime_zone();
424 ZoneScope zone_scope(zone, DELETE_ON_EXIT);
425 ZoneList<Code*> codes(1, zone);
426 DeoptimizeWithMatchingCodeFilter filter(code);
427 PartitionOptimizedFunctions(context, &filter, &codes, zone, undefined);
428 ASSERT_EQ(1, codes.length());
429 DeoptimizeFunctionWithPreparedFunctionList(
430 JSFunction::cast(codes.at(0)->deoptimizing_functions()));
431 codes.at(0)->set_deoptimizing_functions(undefined);
432}
433
434
435void Deoptimizer::DeoptimizeAllFunctionsForContext(
436 Context* context, OptimizedFunctionFilter* filter) {
437 ASSERT(context->IsNativeContext());
438 Isolate* isolate = context->GetIsolate();
439 Object* undefined = isolate->heap()->undefined_value();
440 Zone* zone = isolate->runtime_zone();
441 ZoneScope zone_scope(zone, DELETE_ON_EXIT);
442 ZoneList<Code*> codes(1, zone);
443 PartitionOptimizedFunctions(context, filter, &codes, zone, undefined);
444 for (int i = 0; i < codes.length(); ++i) {
445 DeoptimizeFunctionWithPreparedFunctionList(
446 JSFunction::cast(codes.at(i)->deoptimizing_functions()));
447 codes.at(i)->set_deoptimizing_functions(undefined);
448 }
449}
450
451
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000452void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate,
453 OptimizedFunctionFilter* filter) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000454 DisallowHeapAllocation no_allocation;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000455
456 // Run through the list of all native contexts and deoptimize.
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000457 Object* context = isolate->heap()->native_contexts_list();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000458 while (!context->IsUndefined()) {
459 DeoptimizeAllFunctionsForContext(Context::cast(context), filter);
460 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
461 }
462}
463
464
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000465void Deoptimizer::HandleWeakDeoptimizedCode(v8::Isolate* isolate,
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000466 v8::Persistent<v8::Value>* obj,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000467 void* parameter) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000468 DeoptimizingCodeListNode* node =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000469 reinterpret_cast<DeoptimizingCodeListNode*>(parameter);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000470 DeoptimizerData* data =
471 reinterpret_cast<Isolate*>(isolate)->deoptimizer_data();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000472 data->RemoveDeoptimizingCode(*node->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000473#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000474 for (DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
475 current != NULL;
476 current = current->next()) {
477 ASSERT(current != node);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000478 }
479#endif
480}
481
482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000483void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000484 deoptimizer->DoComputeOutputFrames();
485}
486
487
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000488bool Deoptimizer::TraceEnabledFor(BailoutType deopt_type,
489 StackFrame::Type frame_type) {
490 switch (deopt_type) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000491 case EAGER:
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000492 case SOFT:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000493 case LAZY:
494 case DEBUGGER:
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000495 return (frame_type == StackFrame::STUB)
496 ? FLAG_trace_stub_failures
497 : FLAG_trace_deopt;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000498 case OSR:
499 return FLAG_trace_osr;
500 }
501 UNREACHABLE();
502 return false;
503}
504
505
506const char* Deoptimizer::MessageFor(BailoutType type) {
507 switch (type) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000508 case EAGER: return "eager";
509 case SOFT: return "soft";
510 case LAZY: return "lazy";
511 case DEBUGGER: return "debugger";
512 case OSR: return "OSR";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000513 }
514 UNREACHABLE();
ulan@chromium.org4121f232012-12-27 15:57:11 +0000515 return NULL;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000516}
517
518
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519Deoptimizer::Deoptimizer(Isolate* isolate,
520 JSFunction* function,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000521 BailoutType type,
522 unsigned bailout_id,
523 Address from,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000524 int fp_to_sp_delta,
525 Code* optimized_code)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526 : isolate_(isolate),
527 function_(function),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000528 bailout_id_(bailout_id),
529 bailout_type_(type),
530 from_(from),
531 fp_to_sp_delta_(fp_to_sp_delta),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000532 has_alignment_padding_(0),
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000533 input_(NULL),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000534 output_count_(0),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000535 jsframe_count_(0),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000536 output_(NULL),
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000537 deferred_objects_tagged_values_(0),
538 deferred_objects_double_values_(0),
539 deferred_objects_(0),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000540 deferred_heap_numbers_(0),
541 trace_(false) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000542 // For COMPILED_STUBs called from builtins, the function pointer is a SMI
543 // indicating an internal frame.
544 if (function->IsSmi()) {
545 function = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000546 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000547 if (function != NULL && function->IsOptimized()) {
548 function->shared()->increment_deopt_count();
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000549 if (bailout_type_ == Deoptimizer::SOFT) {
550 // Soft deopts shouldn't count against the overall re-optimization count
551 // that can eventually lead to disabling optimization for a function.
552 int opt_count = function->shared()->opt_count();
553 if (opt_count > 0) opt_count--;
554 function->shared()->set_opt_count(opt_count);
555 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000556 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000557 compiled_code_ = FindOptimizedCode(function, optimized_code);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000558 StackFrame::Type frame_type = function == NULL
559 ? StackFrame::STUB
560 : StackFrame::JAVA_SCRIPT;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000561 trace_ = TraceEnabledFor(type, frame_type);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000562#ifdef DEBUG
563 CHECK(AllowHeapAllocation::IsAllowed());
564 disallow_heap_allocation_ = new DisallowHeapAllocation();
565#endif // DEBUG
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000566 unsigned size = ComputeInputFrameSize();
567 input_ = new(size) FrameDescription(size, function);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000568 input_->SetFrameType(frame_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000569}
570
571
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000572Code* Deoptimizer::FindOptimizedCode(JSFunction* function,
573 Code* optimized_code) {
574 switch (bailout_type_) {
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000575 case Deoptimizer::SOFT:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000576 case Deoptimizer::EAGER:
577 ASSERT(from_ == NULL);
578 return function->code();
579 case Deoptimizer::LAZY: {
580 Code* compiled_code =
581 isolate_->deoptimizer_data()->FindDeoptimizingCode(from_);
582 return (compiled_code == NULL)
583 ? static_cast<Code*>(isolate_->heap()->FindCodeObject(from_))
584 : compiled_code;
585 }
586 case Deoptimizer::OSR: {
587 // The function has already been optimized and we're transitioning
588 // from the unoptimized shared version to the optimized one in the
589 // function. The return address (from_) points to unoptimized code.
590 Code* compiled_code = function->code();
591 ASSERT(compiled_code->kind() == Code::OPTIMIZED_FUNCTION);
592 ASSERT(!compiled_code->contains(from_));
593 return compiled_code;
594 }
595 case Deoptimizer::DEBUGGER:
596 ASSERT(optimized_code->contains(from_));
597 return optimized_code;
598 }
599 UNREACHABLE();
600 return NULL;
601}
602
603
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000604void Deoptimizer::PrintFunctionName() {
605 if (function_->IsJSFunction()) {
606 function_->PrintName();
607 } else {
608 PrintF("%s", Code::Kind2String(compiled_code_->kind()));
609 }
610}
611
612
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000613Deoptimizer::~Deoptimizer() {
614 ASSERT(input_ == NULL && output_ == NULL);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000615 ASSERT(disallow_heap_allocation_ == NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000616}
617
618
619void Deoptimizer::DeleteFrameDescriptions() {
620 delete input_;
621 for (int i = 0; i < output_count_; ++i) {
622 if (output_[i] != input_) delete output_[i];
623 }
624 delete[] output_;
625 input_ = NULL;
626 output_ = NULL;
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000627#ifdef DEBUG
628 CHECK(!AllowHeapAllocation::IsAllowed());
629 CHECK(disallow_heap_allocation_ != NULL);
630 delete disallow_heap_allocation_;
631 disallow_heap_allocation_ = NULL;
632#endif // DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000633}
634
635
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000636Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
637 int id,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000638 BailoutType type,
639 GetEntryMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000640 ASSERT(id >= 0);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000641 if (id >= kMaxNumberOfEntries) return NULL;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000642 if (mode == ENSURE_ENTRY_CODE) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000643 EnsureCodeForDeoptimizationEntry(isolate, type, id);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000644 } else {
645 ASSERT(mode == CALCULATE_ENTRY_ADDRESS);
646 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000647 DeoptimizerData* data = isolate->deoptimizer_data();
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000648 ASSERT(type < kBailoutTypesWithCodeEntry);
649 MemoryChunk* base = data->deopt_entry_code_[type];
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000650 return base->area_start() + (id * table_entry_size_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000651}
652
653
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000654int Deoptimizer::GetDeoptimizationId(Isolate* isolate,
655 Address addr,
656 BailoutType type) {
657 DeoptimizerData* data = isolate->deoptimizer_data();
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000658 MemoryChunk* base = data->deopt_entry_code_[type];
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000659 Address start = base->area_start();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000660 if (base == NULL ||
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000661 addr < start ||
662 addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000663 return kNotDeoptimizationEntry;
664 }
665 ASSERT_EQ(0,
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000666 static_cast<int>(addr - start) % table_entry_size_);
667 return static_cast<int>(addr - start) / table_entry_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000668}
669
670
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000671int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000672 BailoutId id,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000673 SharedFunctionInfo* shared) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000674 // TODO(kasperl): For now, we do a simple linear search for the PC
675 // offset associated with the given node id. This should probably be
676 // changed to a binary search.
677 int length = data->DeoptPoints();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678 for (int i = 0; i < length; i++) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000679 if (data->AstId(i) == id) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000680 return data->PcAndState(i)->value();
681 }
682 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000683 PrintF("[couldn't find pc offset for node=%d]\n", id.ToInt());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000684 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
685 // Print the source code if available.
686 HeapStringAllocator string_allocator;
687 StringStream stream(&string_allocator);
688 shared->SourceCodePrint(&stream, -1);
689 PrintF("[source:\n%s\n]", *stream.ToCString());
690
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000691 FATAL("unable to find pc offset during deoptimization");
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000692 return -1;
693}
694
695
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000696int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000697 int length = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 DeoptimizingCodeListNode* node =
699 isolate->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000700 while (node != NULL) {
701 length++;
702 node = node->next();
703 }
704 return length;
705}
706
707
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000708// We rely on this function not causing a GC. It is called from generated code
709// without having a real stack frame in place.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000710void Deoptimizer::DoComputeOutputFrames() {
711 if (bailout_type_ == OSR) {
712 DoComputeOsrOutputFrame();
713 return;
714 }
715
716 // Print some helpful diagnostic information.
717 int64_t start = OS::Ticks();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000718 if (trace_) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000719 PrintF("[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
720 MessageFor(bailout_type_),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000721 reinterpret_cast<intptr_t>(function_));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000722 PrintFunctionName();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000723 PrintF(" @%d, FP to SP delta: %d]\n", bailout_id_, fp_to_sp_delta_);
724 if (bailout_type_ == EAGER || bailout_type_ == SOFT) {
725 compiled_code_->PrintDeoptLocation(bailout_id_);
726 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000727 }
728
729 // Determine basic deoptimization information. The optimized frame is
730 // described by the input data.
731 DeoptimizationInputData* input_data =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000732 DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000733 BailoutId node_id = input_data->AstId(bailout_id_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000734 ByteArray* translations = input_data->TranslationByteArray();
735 unsigned translation_index =
736 input_data->TranslationIndex(bailout_id_)->value();
737
738 // Do the input frame to output frame(s) translation.
739 TranslationIterator iterator(translations, translation_index);
740 Translation::Opcode opcode =
741 static_cast<Translation::Opcode>(iterator.Next());
742 ASSERT(Translation::BEGIN == opcode);
743 USE(opcode);
744 // Read the number of output frames and allocate an array for their
745 // descriptions.
746 int count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000747 iterator.Next(); // Drop JS frames count.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000748 ASSERT(output_ == NULL);
749 output_ = new FrameDescription*[count];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000750 for (int i = 0; i < count; ++i) {
751 output_[i] = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000752 }
753 output_count_ = count;
754
755 // Translate each output frame.
756 for (int i = 0; i < count; ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000757 // Read the ast node id, function, and frame height for this output frame.
758 Translation::Opcode opcode =
759 static_cast<Translation::Opcode>(iterator.Next());
760 switch (opcode) {
761 case Translation::JS_FRAME:
762 DoComputeJSFrame(&iterator, i);
763 jsframe_count_++;
764 break;
765 case Translation::ARGUMENTS_ADAPTOR_FRAME:
766 DoComputeArgumentsAdaptorFrame(&iterator, i);
767 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000768 case Translation::CONSTRUCT_STUB_FRAME:
769 DoComputeConstructStubFrame(&iterator, i);
770 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000771 case Translation::GETTER_STUB_FRAME:
772 DoComputeAccessorStubFrame(&iterator, i, false);
773 break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000774 case Translation::SETTER_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000775 DoComputeAccessorStubFrame(&iterator, i, true);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000776 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000777 case Translation::COMPILED_STUB_FRAME:
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000778 DoComputeCompiledStubFrame(&iterator, i);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000779 break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000780 case Translation::BEGIN:
781 case Translation::REGISTER:
782 case Translation::INT32_REGISTER:
783 case Translation::UINT32_REGISTER:
784 case Translation::DOUBLE_REGISTER:
785 case Translation::STACK_SLOT:
786 case Translation::INT32_STACK_SLOT:
787 case Translation::UINT32_STACK_SLOT:
788 case Translation::DOUBLE_STACK_SLOT:
789 case Translation::LITERAL:
790 case Translation::ARGUMENTS_OBJECT:
791 case Translation::DUPLICATE:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000792 default:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000793 UNREACHABLE();
794 break;
795 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000796 }
797
798 // Print some helpful diagnostic information.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000799 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000800 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
801 int index = output_count_ - 1; // Index of the topmost frame.
802 JSFunction* function = output_[index]->GetFunction();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000803 PrintF("[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
804 MessageFor(bailout_type_),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000805 reinterpret_cast<intptr_t>(function));
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000806 PrintFunctionName();
807 PrintF(" @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000808 " took %0.3f ms]\n",
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000809 bailout_id_,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000810 node_id.ToInt(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000811 output_[index]->GetPc(),
812 FullCodeGenerator::State2String(
813 static_cast<FullCodeGenerator::State>(
814 output_[index]->GetState()->value())),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000815 has_alignment_padding_ ? "with padding" : "no padding",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000816 ms);
817 }
818}
819
820
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000821void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
822 int frame_index) {
823 BailoutId node_id = BailoutId(iterator->Next());
824 JSFunction* function;
825 if (frame_index != 0) {
826 function = JSFunction::cast(ComputeLiteral(iterator->Next()));
827 } else {
828 int closure_id = iterator->Next();
829 USE(closure_id);
830 ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
831 function = function_;
832 }
833 unsigned height = iterator->Next();
834 unsigned height_in_bytes = height * kPointerSize;
835 if (trace_) {
836 PrintF(" translating ");
837 function->PrintName();
838 PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
839 }
840
841 // The 'fixed' part of the frame consists of the incoming parameters and
842 // the part described by JavaScriptFrameConstants.
843 unsigned fixed_frame_size = ComputeFixedSize(function);
844 unsigned input_frame_size = input_->GetFrameSize();
845 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
846
847 // Allocate and store the output frame description.
848 FrameDescription* output_frame =
849 new(output_frame_size) FrameDescription(output_frame_size, function);
850 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
851
852 bool is_bottommost = (0 == frame_index);
853 bool is_topmost = (output_count_ - 1 == frame_index);
854 ASSERT(frame_index >= 0 && frame_index < output_count_);
855 ASSERT(output_[frame_index] == NULL);
856 output_[frame_index] = output_frame;
857
858 // The top address for the bottommost output frame can be computed from
859 // the input frame pointer and the output frame's height. For all
860 // subsequent output frames, it can be computed from the previous one's
861 // top address and the current frame's size.
862 Register fp_reg = JavaScriptFrame::fp_register();
863 intptr_t top_address;
864 if (is_bottommost) {
865 // Determine whether the input frame contains alignment padding.
866 has_alignment_padding_ = HasAlignmentPadding(function) ? 1 : 0;
867 // 2 = context and function in the frame.
868 // If the optimized frame had alignment padding, adjust the frame pointer
869 // to point to the new position of the old frame pointer after padding
870 // is removed. Subtract 2 * kPointerSize for the context and function slots.
871 top_address = input_->GetRegister(fp_reg.code()) - (2 * kPointerSize) -
872 height_in_bytes + has_alignment_padding_ * kPointerSize;
873 } else {
874 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
875 }
876 output_frame->SetTop(top_address);
877
878 // Compute the incoming parameter translation.
879 int parameter_count = function->shared()->formal_parameter_count() + 1;
880 unsigned output_offset = output_frame_size;
881 unsigned input_offset = input_frame_size;
882 for (int i = 0; i < parameter_count; ++i) {
883 output_offset -= kPointerSize;
884 DoTranslateCommand(iterator, frame_index, output_offset);
885 }
886 input_offset -= (parameter_count * kPointerSize);
887
888 // There are no translation commands for the caller's pc and fp, the
889 // context, and the function. Synthesize their values and set them up
890 // explicitly.
891 //
892 // The caller's pc for the bottommost output frame is the same as in the
893 // input frame. For all subsequent output frames, it can be read from the
894 // previous one. This frame's pc can be computed from the non-optimized
895 // function code and AST id of the bailout.
896 output_offset -= kPointerSize;
897 input_offset -= kPointerSize;
898 intptr_t value;
899 if (is_bottommost) {
900 value = input_->GetFrameSlot(input_offset);
901 } else {
902 value = output_[frame_index - 1]->GetPc();
903 }
904 output_frame->SetFrameSlot(output_offset, value);
905 if (trace_) {
906 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
907 V8PRIxPTR " ; caller's pc\n",
908 top_address + output_offset, output_offset, value);
909 }
910
911 // The caller's frame pointer for the bottommost output frame is the same
912 // as in the input frame. For all subsequent output frames, it can be
913 // read from the previous one. Also compute and set this frame's frame
914 // pointer.
915 output_offset -= kPointerSize;
916 input_offset -= kPointerSize;
917 if (is_bottommost) {
918 value = input_->GetFrameSlot(input_offset);
919 } else {
920 value = output_[frame_index - 1]->GetFp();
921 }
922 output_frame->SetFrameSlot(output_offset, value);
923 intptr_t fp_value = top_address + output_offset;
924 ASSERT(!is_bottommost || (input_->GetRegister(fp_reg.code()) +
925 has_alignment_padding_ * kPointerSize) == fp_value);
926 output_frame->SetFp(fp_value);
927 if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
928 if (trace_) {
929 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
930 V8PRIxPTR " ; caller's fp\n",
931 fp_value, output_offset, value);
932 }
933 ASSERT(!is_bottommost || !has_alignment_padding_ ||
934 (fp_value & kPointerSize) != 0);
935
936 // For the bottommost output frame the context can be gotten from the input
937 // frame. For all subsequent output frames it can be gotten from the function
938 // so long as we don't inline functions that need local contexts.
939 Register context_reg = JavaScriptFrame::context_register();
940 output_offset -= kPointerSize;
941 input_offset -= kPointerSize;
942 if (is_bottommost) {
943 value = input_->GetFrameSlot(input_offset);
944 } else {
945 value = reinterpret_cast<intptr_t>(function->context());
946 }
947 output_frame->SetFrameSlot(output_offset, value);
948 output_frame->SetContext(value);
949 if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
950 if (trace_) {
951 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
952 V8PRIxPTR "; context\n",
953 top_address + output_offset, output_offset, value);
954 }
955
956 // The function was mentioned explicitly in the BEGIN_FRAME.
957 output_offset -= kPointerSize;
958 input_offset -= kPointerSize;
959 value = reinterpret_cast<intptr_t>(function);
960 // The function for the bottommost output frame should also agree with the
961 // input frame.
962 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
963 output_frame->SetFrameSlot(output_offset, value);
964 if (trace_) {
965 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
966 V8PRIxPTR "; function\n",
967 top_address + output_offset, output_offset, value);
968 }
969
970 // Translate the rest of the frame.
971 for (unsigned i = 0; i < height; ++i) {
972 output_offset -= kPointerSize;
973 DoTranslateCommand(iterator, frame_index, output_offset);
974 }
975 ASSERT(0 == output_offset);
976
977 // Compute this frame's PC, state, and continuation.
978 Code* non_optimized_code = function->shared()->code();
979 FixedArray* raw_data = non_optimized_code->deoptimization_data();
980 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
981 Address start = non_optimized_code->instruction_start();
982 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
983 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
984 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
985 output_frame->SetPc(pc_value);
986
987 FullCodeGenerator::State state =
988 FullCodeGenerator::StateField::decode(pc_and_state);
989 output_frame->SetState(Smi::FromInt(state));
990
991 // Set the continuation for the topmost frame.
992 if (is_topmost && bailout_type_ != DEBUGGER) {
993 Builtins* builtins = isolate_->builtins();
994 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
995 if (bailout_type_ == LAZY) {
996 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
997 } else if (bailout_type_ == SOFT) {
998 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
999 } else {
1000 ASSERT(bailout_type_ == EAGER);
1001 }
1002 output_frame->SetContinuation(
1003 reinterpret_cast<intptr_t>(continuation->entry()));
1004 }
1005}
1006
1007
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001008void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
1009 int frame_index) {
1010 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
1011 unsigned height = iterator->Next();
1012 unsigned height_in_bytes = height * kPointerSize;
1013 if (trace_) {
1014 PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
1015 }
1016
1017 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
1018 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1019
1020 // Allocate and store the output frame description.
1021 FrameDescription* output_frame =
1022 new(output_frame_size) FrameDescription(output_frame_size, function);
1023 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
1024
1025 // Arguments adaptor can not be topmost or bottommost.
1026 ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
1027 ASSERT(output_[frame_index] == NULL);
1028 output_[frame_index] = output_frame;
1029
1030 // The top address of the frame is computed from the previous
1031 // frame's top and this frame's size.
1032 intptr_t top_address;
1033 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1034 output_frame->SetTop(top_address);
1035
1036 // Compute the incoming parameter translation.
1037 int parameter_count = height;
1038 unsigned output_offset = output_frame_size;
1039 for (int i = 0; i < parameter_count; ++i) {
1040 output_offset -= kPointerSize;
1041 DoTranslateCommand(iterator, frame_index, output_offset);
1042 }
1043
1044 // Read caller's PC from the previous frame.
1045 output_offset -= kPointerSize;
1046 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1047 output_frame->SetFrameSlot(output_offset, callers_pc);
1048 if (trace_) {
1049 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1050 V8PRIxPTR " ; caller's pc\n",
1051 top_address + output_offset, output_offset, callers_pc);
1052 }
1053
1054 // Read caller's FP from the previous frame, and set this frame's FP.
1055 output_offset -= kPointerSize;
1056 intptr_t value = output_[frame_index - 1]->GetFp();
1057 output_frame->SetFrameSlot(output_offset, value);
1058 intptr_t fp_value = top_address + output_offset;
1059 output_frame->SetFp(fp_value);
1060 if (trace_) {
1061 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1062 V8PRIxPTR " ; caller's fp\n",
1063 fp_value, output_offset, value);
1064 }
1065
1066 // A marker value is used in place of the context.
1067 output_offset -= kPointerSize;
1068 intptr_t context = reinterpret_cast<intptr_t>(
1069 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1070 output_frame->SetFrameSlot(output_offset, context);
1071 if (trace_) {
1072 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1073 V8PRIxPTR " ; context (adaptor sentinel)\n",
1074 top_address + output_offset, output_offset, context);
1075 }
1076
1077 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
1078 output_offset -= kPointerSize;
1079 value = reinterpret_cast<intptr_t>(function);
1080 output_frame->SetFrameSlot(output_offset, value);
1081 if (trace_) {
1082 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1083 V8PRIxPTR " ; function\n",
1084 top_address + output_offset, output_offset, value);
1085 }
1086
1087 // Number of incoming arguments.
1088 output_offset -= kPointerSize;
1089 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1090 output_frame->SetFrameSlot(output_offset, value);
1091 if (trace_) {
1092 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1093 V8PRIxPTR " ; argc (%d)\n",
1094 top_address + output_offset, output_offset, value, height - 1);
1095 }
1096
1097 ASSERT(0 == output_offset);
1098
1099 Builtins* builtins = isolate_->builtins();
1100 Code* adaptor_trampoline =
1101 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
1102 intptr_t pc_value = reinterpret_cast<intptr_t>(
1103 adaptor_trampoline->instruction_start() +
1104 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
1105 output_frame->SetPc(pc_value);
1106}
1107
1108
ulan@chromium.org750145a2013-03-07 15:14:13 +00001109void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
1110 int frame_index) {
1111 Builtins* builtins = isolate_->builtins();
1112 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
1113 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
1114 unsigned height = iterator->Next();
1115 unsigned height_in_bytes = height * kPointerSize;
1116 if (trace_) {
1117 PrintF(" translating construct stub => height=%d\n", height_in_bytes);
1118 }
1119
1120 unsigned fixed_frame_size = ConstructFrameConstants::kFrameSize;
1121 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1122
1123 // Allocate and store the output frame description.
1124 FrameDescription* output_frame =
1125 new(output_frame_size) FrameDescription(output_frame_size, function);
1126 output_frame->SetFrameType(StackFrame::CONSTRUCT);
1127
1128 // Construct stub can not be topmost or bottommost.
1129 ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
1130 ASSERT(output_[frame_index] == NULL);
1131 output_[frame_index] = output_frame;
1132
1133 // The top address of the frame is computed from the previous
1134 // frame's top and this frame's size.
1135 intptr_t top_address;
1136 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1137 output_frame->SetTop(top_address);
1138
1139 // Compute the incoming parameter translation.
1140 int parameter_count = height;
1141 unsigned output_offset = output_frame_size;
1142 for (int i = 0; i < parameter_count; ++i) {
1143 output_offset -= kPointerSize;
1144 DoTranslateCommand(iterator, frame_index, output_offset);
1145 }
1146
1147 // Read caller's PC from the previous frame.
1148 output_offset -= kPointerSize;
1149 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1150 output_frame->SetFrameSlot(output_offset, callers_pc);
1151 if (trace_) {
1152 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1153 V8PRIxPTR " ; caller's pc\n",
1154 top_address + output_offset, output_offset, callers_pc);
1155 }
1156
1157 // Read caller's FP from the previous frame, and set this frame's FP.
1158 output_offset -= kPointerSize;
1159 intptr_t value = output_[frame_index - 1]->GetFp();
1160 output_frame->SetFrameSlot(output_offset, value);
1161 intptr_t fp_value = top_address + output_offset;
1162 output_frame->SetFp(fp_value);
1163 if (trace_) {
1164 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1165 V8PRIxPTR " ; caller's fp\n",
1166 fp_value, output_offset, value);
1167 }
1168
1169 // The context can be gotten from the previous frame.
1170 output_offset -= kPointerSize;
1171 value = output_[frame_index - 1]->GetContext();
1172 output_frame->SetFrameSlot(output_offset, value);
1173 if (trace_) {
1174 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1175 V8PRIxPTR " ; context\n",
1176 top_address + output_offset, output_offset, value);
1177 }
1178
1179 // A marker value is used in place of the function.
1180 output_offset -= kPointerSize;
1181 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
1182 output_frame->SetFrameSlot(output_offset, value);
1183 if (trace_) {
1184 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1185 V8PRIxPTR " ; function (construct sentinel)\n",
1186 top_address + output_offset, output_offset, value);
1187 }
1188
1189 // The output frame reflects a JSConstructStubGeneric frame.
1190 output_offset -= kPointerSize;
1191 value = reinterpret_cast<intptr_t>(construct_stub);
1192 output_frame->SetFrameSlot(output_offset, value);
1193 if (trace_) {
1194 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1195 V8PRIxPTR " ; code object\n",
1196 top_address + output_offset, output_offset, value);
1197 }
1198
1199 // Number of incoming arguments.
1200 output_offset -= kPointerSize;
1201 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1202 output_frame->SetFrameSlot(output_offset, value);
1203 if (trace_) {
1204 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1205 V8PRIxPTR " ; argc (%d)\n",
1206 top_address + output_offset, output_offset, value, height - 1);
1207 }
1208
1209 // Constructor function being invoked by the stub (only present on some
1210 // architectures, indicated by kConstructorOffset).
1211 if (ConstructFrameConstants::kConstructorOffset != kMinInt) {
1212 output_offset -= kPointerSize;
1213 value = reinterpret_cast<intptr_t>(function);
1214 output_frame->SetFrameSlot(output_offset, value);
1215 if (trace_) {
1216 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1217 V8PRIxPTR " ; constructor function\n",
1218 top_address + output_offset, output_offset, value);
1219 }
1220 }
1221
1222 // The newly allocated object was passed as receiver in the artificial
1223 // constructor stub environment created by HEnvironment::CopyForInlining().
1224 output_offset -= kPointerSize;
1225 value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
1226 output_frame->SetFrameSlot(output_offset, value);
1227 if (trace_) {
1228 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1229 V8PRIxPTR " ; allocated receiver\n",
1230 top_address + output_offset, output_offset, value);
1231 }
1232
1233 ASSERT(0 == output_offset);
1234
1235 intptr_t pc = reinterpret_cast<intptr_t>(
1236 construct_stub->instruction_start() +
1237 isolate_->heap()->construct_stub_deopt_pc_offset()->value());
1238 output_frame->SetPc(pc);
1239}
1240
1241
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001242void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
1243 int frame_index,
1244 bool is_setter_stub_frame) {
1245 JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
1246 // The receiver (and the implicit return value, if any) are expected in
1247 // registers by the LoadIC/StoreIC, so they don't belong to the output stack
1248 // frame. This means that we have to use a height of 0.
1249 unsigned height = 0;
1250 unsigned height_in_bytes = height * kPointerSize;
1251 const char* kind = is_setter_stub_frame ? "setter" : "getter";
1252 if (trace_) {
1253 PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
1254 }
1255
1256 // We need 1 stack entry for the return address + 4 stack entries from
1257 // StackFrame::INTERNAL (FP, context, frame type, code object, see
1258 // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
1259 // entry for the implicit return value, see
1260 // StoreStubCompiler::CompileStoreViaSetter.
1261 unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
1262 unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
1263 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1264
1265 // Allocate and store the output frame description.
1266 FrameDescription* output_frame =
1267 new(output_frame_size) FrameDescription(output_frame_size, accessor);
1268 output_frame->SetFrameType(StackFrame::INTERNAL);
1269
1270 // A frame for an accessor stub can not be the topmost or bottommost one.
1271 ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
1272 ASSERT(output_[frame_index] == NULL);
1273 output_[frame_index] = output_frame;
1274
1275 // The top address of the frame is computed from the previous frame's top and
1276 // this frame's size.
1277 intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1278 output_frame->SetTop(top_address);
1279
1280 unsigned output_offset = output_frame_size;
1281
1282 // Read caller's PC from the previous frame.
1283 output_offset -= kPointerSize;
1284 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1285 output_frame->SetFrameSlot(output_offset, callers_pc);
1286 if (trace_) {
1287 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1288 " ; caller's pc\n",
1289 top_address + output_offset, output_offset, callers_pc);
1290 }
1291
1292 // Read caller's FP from the previous frame, and set this frame's FP.
1293 output_offset -= kPointerSize;
1294 intptr_t value = output_[frame_index - 1]->GetFp();
1295 output_frame->SetFrameSlot(output_offset, value);
1296 intptr_t fp_value = top_address + output_offset;
1297 output_frame->SetFp(fp_value);
1298 if (trace_) {
1299 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1300 " ; caller's fp\n",
1301 fp_value, output_offset, value);
1302 }
1303
1304 // The context can be gotten from the previous frame.
1305 output_offset -= kPointerSize;
1306 value = output_[frame_index - 1]->GetContext();
1307 output_frame->SetFrameSlot(output_offset, value);
1308 if (trace_) {
1309 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1310 " ; context\n",
1311 top_address + output_offset, output_offset, value);
1312 }
1313
1314 // A marker value is used in place of the function.
1315 output_offset -= kPointerSize;
1316 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
1317 output_frame->SetFrameSlot(output_offset, value);
1318 if (trace_) {
1319 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1320 " ; function (%s sentinel)\n",
1321 top_address + output_offset, output_offset, value, kind);
1322 }
1323
1324 // Get Code object from accessor stub.
1325 output_offset -= kPointerSize;
1326 Builtins::Name name = is_setter_stub_frame ?
1327 Builtins::kStoreIC_Setter_ForDeopt :
1328 Builtins::kLoadIC_Getter_ForDeopt;
1329 Code* accessor_stub = isolate_->builtins()->builtin(name);
1330 value = reinterpret_cast<intptr_t>(accessor_stub);
1331 output_frame->SetFrameSlot(output_offset, value);
1332 if (trace_) {
1333 PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1334 " ; code object\n",
1335 top_address + output_offset, output_offset, value);
1336 }
1337
1338 // Skip receiver.
1339 Translation::Opcode opcode =
1340 static_cast<Translation::Opcode>(iterator->Next());
1341 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
1342
1343 if (is_setter_stub_frame) {
1344 // The implicit return value was part of the artificial setter stub
1345 // environment.
1346 output_offset -= kPointerSize;
1347 DoTranslateCommand(iterator, frame_index, output_offset);
1348 }
1349
1350 ASSERT(0 == output_offset);
1351
1352 Smi* offset = is_setter_stub_frame ?
1353 isolate_->heap()->setter_stub_deopt_pc_offset() :
1354 isolate_->heap()->getter_stub_deopt_pc_offset();
1355 intptr_t pc = reinterpret_cast<intptr_t>(
1356 accessor_stub->instruction_start() + offset->value());
1357 output_frame->SetPc(pc);
1358}
1359
1360
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001361void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
1362 int frame_index) {
1363 //
1364 // FROM TO
1365 // | .... | | .... |
1366 // +-------------------------+ +-------------------------+
1367 // | JSFunction continuation | | JSFunction continuation |
1368 // +-------------------------+ +-------------------------+
1369 // | | saved frame (FP) | | saved frame (FP) |
1370 // | +=========================+<-fpreg +=========================+<-fpreg
1371 // | | JSFunction context | | JSFunction context |
1372 // v +-------------------------+ +-------------------------|
1373 // | COMPILED_STUB marker | | STUB_FAILURE marker |
1374 // +-------------------------+ +-------------------------+
1375 // | | | caller args.arguments_ |
1376 // | ... | +-------------------------+
1377 // | | | caller args.length_ |
1378 // |-------------------------|<-spreg +-------------------------+
1379 // | caller args pointer |
1380 // +-------------------------+
1381 // | caller stack param 1 |
1382 // parameters in registers +-------------------------+
1383 // and spilled to stack | .... |
1384 // +-------------------------+
1385 // | caller stack param n |
1386 // +-------------------------+<-spreg
1387 // reg = number of parameters
1388 // reg = failure handler address
1389 // reg = saved frame
1390 // reg = JSFunction context
1391 //
1392
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001393 ASSERT(compiled_code_->is_crankshafted() &&
1394 compiled_code_->kind() != Code::OPTIMIZED_FUNCTION);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001395 int major_key = compiled_code_->major_key();
1396 CodeStubInterfaceDescriptor* descriptor =
1397 isolate_->code_stub_interface_descriptor(major_key);
1398
1399 // The output frame must have room for all pushed register parameters
1400 // and the standard stack frame slots. Include space for an argument
1401 // object to the callee and optionally the space to pass the argument
1402 // object to the stub failure handler.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001403 ASSERT(descriptor->register_param_count_ >= 0);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001404 int height_in_bytes = kPointerSize * descriptor->register_param_count_ +
1405 sizeof(Arguments) + kPointerSize;
1406 int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
1407 int input_frame_size = input_->GetFrameSize();
1408 int output_frame_size = height_in_bytes + fixed_frame_size;
1409 if (trace_) {
1410 PrintF(" translating %s => StubFailureTrampolineStub, height=%d\n",
1411 CodeStub::MajorName(static_cast<CodeStub::Major>(major_key), false),
1412 height_in_bytes);
1413 }
1414
1415 // The stub failure trampoline is a single frame.
1416 FrameDescription* output_frame =
1417 new(output_frame_size) FrameDescription(output_frame_size, NULL);
1418 output_frame->SetFrameType(StackFrame::STUB_FAILURE_TRAMPOLINE);
1419 ASSERT(frame_index == 0);
1420 output_[frame_index] = output_frame;
1421
1422 // The top address for the output frame can be computed from the input
1423 // frame pointer and the output frame's height. Subtract space for the
1424 // context and function slots.
1425 Register fp_reg = StubFailureTrampolineFrame::fp_register();
1426 intptr_t top_address = input_->GetRegister(fp_reg.code()) -
1427 (2 * kPointerSize) - height_in_bytes;
1428 output_frame->SetTop(top_address);
1429
1430 // Read caller's PC (JSFunction continuation) from the input frame.
1431 unsigned input_frame_offset = input_frame_size - kPointerSize;
1432 unsigned output_frame_offset = output_frame_size - kPointerSize;
1433 intptr_t value = input_->GetFrameSlot(input_frame_offset);
1434 output_frame->SetFrameSlot(output_frame_offset, value);
1435 if (trace_) {
1436 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1437 V8PRIxPTR " ; caller's pc\n",
1438 top_address + output_frame_offset, output_frame_offset, value);
1439 }
1440
1441 // Read caller's FP from the input frame, and set this frame's FP.
1442 input_frame_offset -= kPointerSize;
1443 value = input_->GetFrameSlot(input_frame_offset);
1444 output_frame_offset -= kPointerSize;
1445 output_frame->SetFrameSlot(output_frame_offset, value);
1446 intptr_t frame_ptr = input_->GetRegister(fp_reg.code());
1447 output_frame->SetRegister(fp_reg.code(), frame_ptr);
1448 output_frame->SetFp(frame_ptr);
1449 if (trace_) {
1450 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1451 V8PRIxPTR " ; caller's fp\n",
1452 top_address + output_frame_offset, output_frame_offset, value);
1453 }
1454
1455 // The context can be gotten from the input frame.
1456 Register context_reg = StubFailureTrampolineFrame::context_register();
1457 input_frame_offset -= kPointerSize;
1458 value = input_->GetFrameSlot(input_frame_offset);
1459 output_frame->SetRegister(context_reg.code(), value);
1460 output_frame_offset -= kPointerSize;
1461 output_frame->SetFrameSlot(output_frame_offset, value);
1462 if (trace_) {
1463 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1464 V8PRIxPTR " ; context\n",
1465 top_address + output_frame_offset, output_frame_offset, value);
1466 }
1467
1468 // A marker value is used in place of the function.
1469 output_frame_offset -= kPointerSize;
1470 value = reinterpret_cast<intptr_t>(
1471 Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
1472 output_frame->SetFrameSlot(output_frame_offset, value);
1473 if (trace_) {
1474 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1475 V8PRIxPTR " ; function (stub failure sentinel)\n",
1476 top_address + output_frame_offset, output_frame_offset, value);
1477 }
1478
1479 intptr_t caller_arg_count = 0;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001480 bool arg_count_known = descriptor->stack_parameter_count_ == NULL;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001481
1482 // Build the Arguments object for the caller's parameters and a pointer to it.
1483 output_frame_offset -= kPointerSize;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001484 int args_arguments_offset = output_frame_offset;
1485 intptr_t the_hole = reinterpret_cast<intptr_t>(
1486 isolate_->heap()->the_hole_value());
1487 if (arg_count_known) {
1488 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1489 (caller_arg_count - 1) * kPointerSize;
1490 } else {
1491 value = the_hole;
1492 }
1493
1494 output_frame->SetFrameSlot(args_arguments_offset, value);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001495 if (trace_) {
1496 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001497 V8PRIxPTR " ; args.arguments %s\n",
1498 top_address + args_arguments_offset, args_arguments_offset, value,
1499 arg_count_known ? "" : "(the hole)");
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001500 }
1501
1502 output_frame_offset -= kPointerSize;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001503 int length_frame_offset = output_frame_offset;
1504 value = arg_count_known ? caller_arg_count : the_hole;
1505 output_frame->SetFrameSlot(length_frame_offset, value);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001506 if (trace_) {
1507 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001508 V8PRIxPTR " ; args.length %s\n",
1509 top_address + length_frame_offset, length_frame_offset, value,
1510 arg_count_known ? "" : "(the hole)");
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001511 }
1512
1513 output_frame_offset -= kPointerSize;
1514 value = frame_ptr - (output_frame_size - output_frame_offset) -
1515 StandardFrameConstants::kMarkerOffset + kPointerSize;
1516 output_frame->SetFrameSlot(output_frame_offset, value);
1517 if (trace_) {
1518 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1519 V8PRIxPTR " ; args*\n",
1520 top_address + output_frame_offset, output_frame_offset, value);
1521 }
1522
1523 // Copy the register parameters to the failure frame.
1524 for (int i = 0; i < descriptor->register_param_count_; ++i) {
1525 output_frame_offset -= kPointerSize;
1526 DoTranslateCommand(iterator, 0, output_frame_offset);
1527 }
1528
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001529 if (!arg_count_known) {
1530 DoTranslateCommand(iterator, 0, length_frame_offset,
1531 TRANSLATED_VALUE_IS_NATIVE);
1532 caller_arg_count = output_frame->GetFrameSlot(length_frame_offset);
1533 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1534 (caller_arg_count - 1) * kPointerSize;
1535 output_frame->SetFrameSlot(args_arguments_offset, value);
1536 if (trace_) {
1537 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1538 V8PRIxPTR " ; args.arguments\n",
1539 top_address + args_arguments_offset, args_arguments_offset, value);
1540 }
1541 }
1542
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001543 ASSERT(0 == output_frame_offset);
1544
1545 // Copy the double registers from the input into the output frame.
1546 CopyDoubleRegisters(output_frame);
1547
1548 // Fill registers containing handler and number of parameters.
1549 SetPlatformCompiledStubRegisters(output_frame, descriptor);
1550
1551 // Compute this frame's PC, state, and continuation.
1552 Code* trampoline = NULL;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001553 StubFunctionMode function_mode = descriptor->function_mode_;
1554 StubFailureTrampolineStub(function_mode).FindCodeInCache(&trampoline,
1555 isolate_);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001556 ASSERT(trampoline != NULL);
1557 output_frame->SetPc(reinterpret_cast<intptr_t>(
1558 trampoline->instruction_start()));
1559 output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
1560 Code* notify_failure =
1561 isolate_->builtins()->builtin(Builtins::kNotifyStubFailure);
1562 output_frame->SetContinuation(
1563 reinterpret_cast<intptr_t>(notify_failure->entry()));
1564}
1565
1566
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001567void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001568 ASSERT_NE(DEBUGGER, bailout_type_);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001569
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001570 // Handlify all tagged object values before triggering any allocation.
1571 List<Handle<Object> > values(deferred_objects_tagged_values_.length());
1572 for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) {
1573 values.Add(Handle<Object>(deferred_objects_tagged_values_[i], isolate_));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001574 }
1575
1576 // Play it safe and clear all unhandlified values before we continue.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001577 deferred_objects_tagged_values_.Clear();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001578
1579 // Materialize all heap numbers before looking at arguments because when the
1580 // output frames are used to materialize arguments objects later on they need
1581 // to already contain valid heap numbers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001582 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
1583 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
1584 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001585 if (trace_) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001586 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
1587 reinterpret_cast<void*>(*num),
1588 d.value(),
1589 d.slot_address());
1590 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001591 Memory::Object_at(d.slot_address()) = *num;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001592 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001593
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001594 // Materialize all heap numbers required for arguments objects.
1595 for (int i = 0; i < values.length(); i++) {
1596 if (!values.at(i)->IsTheHole()) continue;
1597 double double_value = deferred_objects_double_values_[i];
1598 Handle<Object> num = isolate_->factory()->NewNumber(double_value);
1599 if (trace_) {
1600 PrintF("Materializing a new heap number %p [%e] for arguments object\n",
1601 reinterpret_cast<void*>(*num), double_value);
1602 }
1603 values.Set(i, num);
1604 }
1605
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001606 // Materialize arguments objects one frame at a time.
1607 for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
1608 if (frame_index != 0) it->Advance();
1609 JavaScriptFrame* frame = it->frame();
1610 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate_);
1611 Handle<JSObject> arguments;
1612 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
1613 if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001614 ObjectMaterializationDescriptor descriptor =
1615 deferred_objects_.RemoveLast();
1616 const int length = descriptor.object_length();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001617 if (arguments.is_null()) {
1618 if (frame->has_adapted_arguments()) {
1619 // Use the arguments adapter frame we just built to materialize the
1620 // arguments object. FunctionGetArguments can't throw an exception,
1621 // so cast away the doubt with an assert.
1622 arguments = Handle<JSObject>(JSObject::cast(
1623 Accessors::FunctionGetArguments(*function,
1624 NULL)->ToObjectUnchecked()));
1625 values.RewindBy(length);
1626 } else {
1627 // Construct an arguments object and copy the parameters to a newly
1628 // allocated arguments object backing store.
1629 arguments =
1630 isolate_->factory()->NewArgumentsObject(function, length);
1631 Handle<FixedArray> array =
1632 isolate_->factory()->NewFixedArray(length);
1633 ASSERT(array->length() == length);
1634 for (int i = length - 1; i >= 0 ; --i) {
1635 array->set(i, *values.RemoveLast());
1636 }
1637 arguments->set_elements(*array);
1638 }
1639 }
1640 frame->SetExpression(i, *arguments);
1641 ASSERT_EQ(Memory::Object_at(descriptor.slot_address()), *arguments);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001642 if (trace_) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001643 PrintF("Materializing %sarguments object of length %d for %p: ",
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001644 frame->has_adapted_arguments() ? "(adapted) " : "",
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001645 arguments->elements()->length(),
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001646 reinterpret_cast<void*>(descriptor.slot_address()));
1647 arguments->ShortPrint();
1648 PrintF("\n");
1649 }
1650 }
1651 }
1652 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001653}
1654
1655
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001656#ifdef ENABLE_DEBUGGER_SUPPORT
1657void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001658 Address parameters_top,
1659 uint32_t parameters_size,
1660 Address expressions_top,
1661 uint32_t expressions_size,
1662 DeoptimizedFrameInfo* info) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001663 ASSERT_EQ(DEBUGGER, bailout_type_);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001664 Address parameters_bottom = parameters_top + parameters_size;
1665 Address expressions_bottom = expressions_top + expressions_size;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001666 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
1667 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
1668
1669 // Check of the heap number to materialize actually belong to the frame
1670 // being extracted.
1671 Address slot = d.slot_address();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001672 if (parameters_top <= slot && slot < parameters_bottom) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001673 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001674
1675 int index = (info->parameters_count() - 1) -
1676 static_cast<int>(slot - parameters_top) / kPointerSize;
1677
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001678 if (trace_) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001679 PrintF("Materializing a new heap number %p [%e] in slot %p"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001680 "for parameter slot #%d\n",
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001681 reinterpret_cast<void*>(*num),
1682 d.value(),
1683 d.slot_address(),
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001684 index);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001685 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001686
1687 info->SetParameter(index, *num);
1688 } else if (expressions_top <= slot && slot < expressions_bottom) {
1689 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
1690
1691 int index = info->expression_count() - 1 -
1692 static_cast<int>(slot - expressions_top) / kPointerSize;
1693
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001694 if (trace_) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001695 PrintF("Materializing a new heap number %p [%e] in slot %p"
1696 "for expression slot #%d\n",
1697 reinterpret_cast<void*>(*num),
1698 d.value(),
1699 d.slot_address(),
1700 index);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001701 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001702
1703 info->SetExpression(index, *num);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001704 }
1705 }
1706}
1707#endif
1708
1709
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001710static const char* TraceValueType(bool is_smi, bool is_native = false) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001711 if (is_native) {
1712 return "native";
1713 } else if (is_smi) {
1714 return "smi";
1715 }
1716
1717 return "heap number";
1718}
1719
1720
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001721void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
1722 int object_opcode,
1723 int field_index) {
1724 disasm::NameConverter converter;
1725 Address object_slot = deferred_objects_.last().slot_address();
1726
1727 // Ignore commands marked as duplicate and act on the first non-duplicate.
1728 Translation::Opcode opcode =
1729 static_cast<Translation::Opcode>(iterator->Next());
1730 while (opcode == Translation::DUPLICATE) {
1731 opcode = static_cast<Translation::Opcode>(iterator->Next());
1732 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
1733 opcode = static_cast<Translation::Opcode>(iterator->Next());
1734 }
1735
1736 switch (opcode) {
1737 case Translation::BEGIN:
1738 case Translation::JS_FRAME:
1739 case Translation::ARGUMENTS_ADAPTOR_FRAME:
1740 case Translation::CONSTRUCT_STUB_FRAME:
1741 case Translation::GETTER_STUB_FRAME:
1742 case Translation::SETTER_STUB_FRAME:
1743 case Translation::COMPILED_STUB_FRAME:
1744 case Translation::ARGUMENTS_OBJECT:
1745 case Translation::DUPLICATE:
1746 UNREACHABLE();
1747 return;
1748
1749 case Translation::REGISTER: {
1750 int input_reg = iterator->Next();
1751 intptr_t input_value = input_->GetRegister(input_reg);
1752 if (trace_) {
1753 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1754 reinterpret_cast<intptr_t>(object_slot),
1755 field_index);
1756 PrintF("0x%08" V8PRIxPTR " ; %s ", input_value,
1757 converter.NameOfCPURegister(input_reg));
1758 reinterpret_cast<Object*>(input_value)->ShortPrint();
1759 PrintF("\n");
1760 }
1761 AddObjectTaggedValue(input_value);
1762 return;
1763 }
1764
1765 case Translation::INT32_REGISTER: {
1766 int input_reg = iterator->Next();
1767 intptr_t value = input_->GetRegister(input_reg);
1768 bool is_smi = Smi::IsValid(value);
1769 if (trace_) {
1770 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1771 reinterpret_cast<intptr_t>(object_slot),
1772 field_index);
1773 PrintF("%" V8PRIdPTR " ; %s (%s)\n", value,
1774 converter.NameOfCPURegister(input_reg),
1775 TraceValueType(is_smi));
1776 }
1777 if (is_smi) {
1778 intptr_t tagged_value =
1779 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1780 AddObjectTaggedValue(tagged_value);
1781 } else {
1782 double double_value = static_cast<double>(static_cast<int32_t>(value));
1783 AddObjectDoubleValue(double_value);
1784 }
1785 return;
1786 }
1787
1788 case Translation::UINT32_REGISTER: {
1789 int input_reg = iterator->Next();
1790 uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
1791 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
1792 if (trace_) {
1793 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1794 reinterpret_cast<intptr_t>(object_slot),
1795 field_index);
1796 PrintF("%" V8PRIdPTR " ; uint %s (%s)\n", value,
1797 converter.NameOfCPURegister(input_reg),
1798 TraceValueType(is_smi));
1799 }
1800 if (is_smi) {
1801 intptr_t tagged_value =
1802 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1803 AddObjectTaggedValue(tagged_value);
1804 } else {
1805 double double_value = static_cast<double>(static_cast<uint32_t>(value));
1806 AddObjectDoubleValue(double_value);
1807 }
1808 return;
1809 }
1810
1811 case Translation::DOUBLE_REGISTER: {
1812 int input_reg = iterator->Next();
1813 double value = input_->GetDoubleRegister(input_reg);
1814 if (trace_) {
1815 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1816 reinterpret_cast<intptr_t>(object_slot),
1817 field_index);
1818 PrintF("%e ; %s\n", value,
1819 DoubleRegister::AllocationIndexToString(input_reg));
1820 }
1821 AddObjectDoubleValue(value);
1822 return;
1823 }
1824
1825 case Translation::STACK_SLOT: {
1826 int input_slot_index = iterator->Next();
1827 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
1828 intptr_t input_value = input_->GetFrameSlot(input_offset);
1829 if (trace_) {
1830 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1831 reinterpret_cast<intptr_t>(object_slot),
1832 field_index);
1833 PrintF("0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
1834 reinterpret_cast<Object*>(input_value)->ShortPrint();
1835 PrintF("\n");
1836 }
1837 AddObjectTaggedValue(input_value);
1838 return;
1839 }
1840
1841 case Translation::INT32_STACK_SLOT: {
1842 int input_slot_index = iterator->Next();
1843 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
1844 intptr_t value = input_->GetFrameSlot(input_offset);
1845 bool is_smi = Smi::IsValid(value);
1846 if (trace_) {
1847 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1848 reinterpret_cast<intptr_t>(object_slot),
1849 field_index);
1850 PrintF("%" V8PRIdPTR " ; [sp + %d] (%s)\n",
1851 value, input_offset, TraceValueType(is_smi));
1852 }
1853 if (is_smi) {
1854 intptr_t tagged_value =
1855 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1856 AddObjectTaggedValue(tagged_value);
1857 } else {
1858 double double_value = static_cast<double>(static_cast<int32_t>(value));
1859 AddObjectDoubleValue(double_value);
1860 }
1861 return;
1862 }
1863
1864 case Translation::UINT32_STACK_SLOT: {
1865 int input_slot_index = iterator->Next();
1866 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
1867 uintptr_t value =
1868 static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
1869 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
1870 if (trace_) {
1871 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1872 reinterpret_cast<intptr_t>(object_slot),
1873 field_index);
1874 PrintF("%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
1875 value, input_offset, TraceValueType(is_smi));
1876 }
1877 if (is_smi) {
1878 intptr_t tagged_value =
1879 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1880 AddObjectTaggedValue(tagged_value);
1881 } else {
1882 double double_value = static_cast<double>(static_cast<uint32_t>(value));
1883 AddObjectDoubleValue(double_value);
1884 }
1885 return;
1886 }
1887
1888 case Translation::DOUBLE_STACK_SLOT: {
1889 int input_slot_index = iterator->Next();
1890 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
1891 double value = input_->GetDoubleFrameSlot(input_offset);
1892 if (trace_) {
1893 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1894 reinterpret_cast<intptr_t>(object_slot),
1895 field_index);
1896 PrintF("%e ; [sp + %d]\n", value, input_offset);
1897 }
1898 AddObjectDoubleValue(value);
1899 return;
1900 }
1901
1902 case Translation::LITERAL: {
1903 Object* literal = ComputeLiteral(iterator->Next());
1904 if (trace_) {
1905 PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
1906 reinterpret_cast<intptr_t>(object_slot),
1907 field_index);
1908 literal->ShortPrint();
1909 PrintF(" ; literal\n");
1910 }
1911 intptr_t value = reinterpret_cast<intptr_t>(literal);
1912 AddObjectTaggedValue(value);
1913 return;
1914 }
1915 }
1916}
1917
1918
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001919void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001920 int frame_index,
1921 unsigned output_offset,
1922 DeoptimizerTranslatedValueType value_type) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001923 disasm::NameConverter converter;
1924 // A GC-safe temporary placeholder that we can put in the output frame.
1925 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001926 bool is_native = value_type == TRANSLATED_VALUE_IS_NATIVE;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001927
1928 // Ignore commands marked as duplicate and act on the first non-duplicate.
1929 Translation::Opcode opcode =
1930 static_cast<Translation::Opcode>(iterator->Next());
1931 while (opcode == Translation::DUPLICATE) {
1932 opcode = static_cast<Translation::Opcode>(iterator->Next());
1933 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
1934 opcode = static_cast<Translation::Opcode>(iterator->Next());
1935 }
1936
1937 switch (opcode) {
1938 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001939 case Translation::JS_FRAME:
1940 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00001941 case Translation::CONSTRUCT_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001942 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001943 case Translation::SETTER_STUB_FRAME:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001944 case Translation::COMPILED_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001945 case Translation::DUPLICATE:
1946 UNREACHABLE();
1947 return;
1948
1949 case Translation::REGISTER: {
1950 int input_reg = iterator->Next();
1951 intptr_t input_value = input_->GetRegister(input_reg);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001952 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001953 PrintF(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001954 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001955 output_[frame_index]->GetTop() + output_offset,
1956 output_offset,
1957 input_value,
1958 converter.NameOfCPURegister(input_reg));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001959 reinterpret_cast<Object*>(input_value)->ShortPrint();
1960 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001961 }
1962 output_[frame_index]->SetFrameSlot(output_offset, input_value);
1963 return;
1964 }
1965
1966 case Translation::INT32_REGISTER: {
1967 int input_reg = iterator->Next();
1968 intptr_t value = input_->GetRegister(input_reg);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001969 bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
1970 Smi::IsValid(value);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001971 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001972 PrintF(
1973 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
1974 output_[frame_index]->GetTop() + output_offset,
1975 output_offset,
1976 value,
1977 converter.NameOfCPURegister(input_reg),
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001978 TraceValueType(is_smi, is_native));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001979 }
1980 if (is_smi) {
1981 intptr_t tagged_value =
1982 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
1983 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001984 } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
1985 output_[frame_index]->SetFrameSlot(output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001986 } else {
1987 // We save the untagged value on the side and store a GC-safe
1988 // temporary placeholder in the frame.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001989 ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001990 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
1991 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001992 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
1993 }
1994 return;
1995 }
1996
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001997 case Translation::UINT32_REGISTER: {
1998 int input_reg = iterator->Next();
1999 uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002000 bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
2001 (value <= static_cast<uintptr_t>(Smi::kMaxValue));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002002 if (trace_) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002003 PrintF(
2004 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
2005 " ; uint %s (%s)\n",
2006 output_[frame_index]->GetTop() + output_offset,
2007 output_offset,
2008 value,
2009 converter.NameOfCPURegister(input_reg),
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002010 TraceValueType(is_smi, is_native));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002011 }
2012 if (is_smi) {
2013 intptr_t tagged_value =
2014 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2015 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002016 } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
2017 output_[frame_index]->SetFrameSlot(output_offset, value);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002018 } else {
2019 // We save the untagged value on the side and store a GC-safe
2020 // temporary placeholder in the frame.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002021 ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002022 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2023 static_cast<double>(static_cast<uint32_t>(value)));
2024 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2025 }
2026 return;
2027 }
2028
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002029 case Translation::DOUBLE_REGISTER: {
2030 int input_reg = iterator->Next();
2031 double value = input_->GetDoubleRegister(input_reg);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002032 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002033 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
2034 output_[frame_index]->GetTop() + output_offset,
2035 output_offset,
2036 value,
2037 DoubleRegister::AllocationIndexToString(input_reg));
2038 }
2039 // We save the untagged value on the side and store a GC-safe
2040 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002041 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002042 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2043 return;
2044 }
2045
2046 case Translation::STACK_SLOT: {
2047 int input_slot_index = iterator->Next();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002048 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002049 intptr_t input_value = input_->GetFrameSlot(input_offset);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002050 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002051 PrintF(" 0x%08" V8PRIxPTR ": ",
2052 output_[frame_index]->GetTop() + output_offset);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002053 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002054 output_offset,
2055 input_value,
2056 input_offset);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002057 reinterpret_cast<Object*>(input_value)->ShortPrint();
2058 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002059 }
2060 output_[frame_index]->SetFrameSlot(output_offset, input_value);
2061 return;
2062 }
2063
2064 case Translation::INT32_STACK_SLOT: {
2065 int input_slot_index = iterator->Next();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002066 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002067 intptr_t value = input_->GetFrameSlot(input_offset);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002068 bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
2069 Smi::IsValid(value);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002070 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002071 PrintF(" 0x%08" V8PRIxPTR ": ",
2072 output_[frame_index]->GetTop() + output_offset);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002073 PrintF("[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002074 output_offset,
2075 value,
2076 input_offset,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002077 TraceValueType(is_smi, is_native));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002078 }
2079 if (is_smi) {
2080 intptr_t tagged_value =
2081 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2082 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002083 } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
2084 output_[frame_index]->SetFrameSlot(output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002085 } else {
2086 // We save the untagged value on the side and store a GC-safe
2087 // temporary placeholder in the frame.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002088 ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002089 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2090 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002091 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2092 }
2093 return;
2094 }
2095
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002096 case Translation::UINT32_STACK_SLOT: {
2097 int input_slot_index = iterator->Next();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002098 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002099 uintptr_t value =
2100 static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002101 bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
2102 (value <= static_cast<uintptr_t>(Smi::kMaxValue));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002103 if (trace_) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002104 PrintF(" 0x%08" V8PRIxPTR ": ",
2105 output_[frame_index]->GetTop() + output_offset);
2106 PrintF("[top + %d] <- %" V8PRIuPTR " ; [sp + %d] (uint32 %s)\n",
2107 output_offset,
2108 value,
2109 input_offset,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002110 TraceValueType(is_smi, is_native));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002111 }
2112 if (is_smi) {
2113 intptr_t tagged_value =
2114 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2115 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002116 } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
2117 output_[frame_index]->SetFrameSlot(output_offset, value);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002118 } else {
2119 // We save the untagged value on the side and store a GC-safe
2120 // temporary placeholder in the frame.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002121 ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002122 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2123 static_cast<double>(static_cast<uint32_t>(value)));
2124 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2125 }
2126 return;
2127 }
2128
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002129 case Translation::DOUBLE_STACK_SLOT: {
2130 int input_slot_index = iterator->Next();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002131 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002132 double value = input_->GetDoubleFrameSlot(input_offset);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002133 if (trace_) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002134 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002135 output_[frame_index]->GetTop() + output_offset,
2136 output_offset,
2137 value,
2138 input_offset);
2139 }
2140 // We save the untagged value on the side and store a GC-safe
2141 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002142 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002143 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2144 return;
2145 }
2146
2147 case Translation::LITERAL: {
2148 Object* literal = ComputeLiteral(iterator->Next());
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002149 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002150 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
2151 output_[frame_index]->GetTop() + output_offset,
2152 output_offset);
2153 literal->ShortPrint();
2154 PrintF(" ; literal\n");
2155 }
2156 intptr_t value = reinterpret_cast<intptr_t>(literal);
2157 output_[frame_index]->SetFrameSlot(output_offset, value);
2158 return;
2159 }
2160
2161 case Translation::ARGUMENTS_OBJECT: {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002162 int length = iterator->Next();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002163 if (trace_) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002164 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
2165 output_[frame_index]->GetTop() + output_offset,
2166 output_offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002167 isolate_->heap()->arguments_marker()->ShortPrint();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002168 PrintF(" ; arguments object (length = %d)\n", length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002169 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002170 // Use the arguments marker value as a sentinel and fill in the arguments
2171 // object after the deoptimized frame is built.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002172 intptr_t value = reinterpret_cast<intptr_t>(
2173 isolate_->heap()->arguments_marker());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002174 AddObjectStart(output_[frame_index]->GetTop() + output_offset, length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002175 output_[frame_index]->SetFrameSlot(output_offset, value);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002176 // We save the argument values on the side and materialize the actual
2177 // arguments object after the deoptimized frame is built.
2178 for (int i = 0; i < length; i++) {
2179 DoTranslateObject(iterator, Translation::ARGUMENTS_OBJECT, i);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002180 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181 return;
2182 }
2183 }
2184}
2185
2186
2187bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
2188 int* input_offset) {
2189 disasm::NameConverter converter;
2190 FrameDescription* output = output_[0];
2191
2192 // The input values are all part of the unoptimized frame so they
2193 // are all tagged pointers.
2194 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
2195 Object* input_object = reinterpret_cast<Object*>(input_value);
2196
2197 Translation::Opcode opcode =
2198 static_cast<Translation::Opcode>(iterator->Next());
2199 bool duplicate = (opcode == Translation::DUPLICATE);
2200 if (duplicate) {
2201 opcode = static_cast<Translation::Opcode>(iterator->Next());
2202 }
2203
2204 switch (opcode) {
2205 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002206 case Translation::JS_FRAME:
2207 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00002208 case Translation::CONSTRUCT_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002209 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002210 case Translation::SETTER_STUB_FRAME:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002211 case Translation::COMPILED_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002212 case Translation::DUPLICATE:
2213 UNREACHABLE(); // Malformed input.
2214 return false;
2215
2216 case Translation::REGISTER: {
2217 int output_reg = iterator->Next();
2218 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002219 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002220 converter.NameOfCPURegister(output_reg),
2221 input_value,
2222 *input_offset);
2223 }
2224 output->SetRegister(output_reg, input_value);
2225 break;
2226 }
2227
2228 case Translation::INT32_REGISTER: {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002229 int32_t int32_value = 0;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002230 if (!input_object->ToInt32(&int32_value)) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002231
2232 int output_reg = iterator->Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002233 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002234 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002235 converter.NameOfCPURegister(output_reg),
2236 int32_value,
2237 *input_offset);
2238 }
2239 output->SetRegister(output_reg, int32_value);
2240 break;
2241 }
2242
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002243 case Translation::UINT32_REGISTER: {
2244 uint32_t uint32_value = 0;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002245 if (!input_object->ToUint32(&uint32_value)) return false;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002246
2247 int output_reg = iterator->Next();
2248 if (FLAG_trace_osr) {
2249 PrintF(" %s <- %u (uint32) ; [sp + %d]\n",
2250 converter.NameOfCPURegister(output_reg),
2251 uint32_value,
2252 *input_offset);
2253 }
2254 output->SetRegister(output_reg, static_cast<int32_t>(uint32_value));
2255 }
2256
2257
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002258 case Translation::DOUBLE_REGISTER: {
2259 // Abort OSR if we don't have a number.
2260 if (!input_object->IsNumber()) return false;
2261
2262 int output_reg = iterator->Next();
2263 double double_value = input_object->Number();
2264 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002265 PrintF(" %s <- %g (double) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002266 DoubleRegister::AllocationIndexToString(output_reg),
2267 double_value,
2268 *input_offset);
2269 }
2270 output->SetDoubleRegister(output_reg, double_value);
2271 break;
2272 }
2273
2274 case Translation::STACK_SLOT: {
2275 int output_index = iterator->Next();
2276 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002277 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002278 if (FLAG_trace_osr) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002279 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002280 output_offset,
2281 input_value,
2282 *input_offset);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002283 reinterpret_cast<Object*>(input_value)->ShortPrint();
2284 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002285 }
2286 output->SetFrameSlot(output_offset, input_value);
2287 break;
2288 }
2289
2290 case Translation::INT32_STACK_SLOT: {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002291 int32_t int32_value = 0;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002292 if (!input_object->ToInt32(&int32_value)) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002293
2294 int output_index = iterator->Next();
2295 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002296 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002297 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002298 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002299 output_offset,
2300 int32_value,
2301 *input_offset);
2302 }
2303 output->SetFrameSlot(output_offset, int32_value);
2304 break;
2305 }
2306
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002307 case Translation::UINT32_STACK_SLOT: {
2308 uint32_t uint32_value = 0;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002309 if (!input_object->ToUint32(&uint32_value)) return false;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002310
2311 int output_index = iterator->Next();
2312 unsigned output_offset =
2313 output->GetOffsetFromSlotIndex(output_index);
2314 if (FLAG_trace_osr) {
2315 PrintF(" [sp + %d] <- %u (uint32) ; [sp + %d]\n",
2316 output_offset,
2317 uint32_value,
2318 *input_offset);
2319 }
2320 output->SetFrameSlot(output_offset, static_cast<int32_t>(uint32_value));
2321 break;
2322 }
2323
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002324 case Translation::DOUBLE_STACK_SLOT: {
2325 static const int kLowerOffset = 0 * kPointerSize;
2326 static const int kUpperOffset = 1 * kPointerSize;
2327
2328 // Abort OSR if we don't have a number.
2329 if (!input_object->IsNumber()) return false;
2330
2331 int output_index = iterator->Next();
2332 unsigned output_offset =
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002333 output->GetOffsetFromSlotIndex(output_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002334 double double_value = input_object->Number();
2335 uint64_t int_value = BitCast<uint64_t, double>(double_value);
2336 int32_t lower = static_cast<int32_t>(int_value);
2337 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
2338 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002339 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002340 output_offset + kUpperOffset,
2341 upper,
2342 double_value,
2343 *input_offset);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002344 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002345 output_offset + kLowerOffset,
2346 lower,
2347 double_value,
2348 *input_offset);
2349 }
2350 output->SetFrameSlot(output_offset + kLowerOffset, lower);
2351 output->SetFrameSlot(output_offset + kUpperOffset, upper);
2352 break;
2353 }
2354
2355 case Translation::LITERAL: {
2356 // Just ignore non-materialized literals.
2357 iterator->Next();
2358 break;
2359 }
2360
2361 case Translation::ARGUMENTS_OBJECT: {
2362 // Optimized code assumes that the argument object has not been
2363 // materialized and so bypasses it when doing arguments access.
2364 // We should have bailed out before starting the frame
2365 // translation.
2366 UNREACHABLE();
2367 return false;
2368 }
2369 }
2370
2371 if (!duplicate) *input_offset -= kPointerSize;
2372 return true;
2373}
2374
2375
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002376void Deoptimizer::PatchInterruptCode(Code* unoptimized_code,
2377 Code* interrupt_code,
2378 Code* replacement_code) {
2379 // Iterate over the back edge table and patch every interrupt
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002380 // call to an unconditional call to the replacement code.
2381 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002382 int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
2383 Address back_edge_cursor = unoptimized_code->instruction_start() +
2384 unoptimized_code->back_edge_table_offset();
2385 uint32_t table_length = Memory::uint32_at(back_edge_cursor);
2386 back_edge_cursor += kIntSize;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002387 for (uint32_t i = 0; i < table_length; ++i) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002388 uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
2389 if (loop_depth == loop_nesting_level) {
2390 // Loop back edge has the loop depth that we want to patch.
2391 uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
2392 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
2393 PatchInterruptCodeAt(unoptimized_code,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002394 pc_after,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002395 interrupt_code,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002396 replacement_code);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002397 }
2398 back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002399 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002400 unoptimized_code->set_back_edges_patched_for_osr(true);
2401#ifdef DEBUG
2402 Deoptimizer::VerifyInterruptCode(
2403 unoptimized_code, interrupt_code, replacement_code, loop_nesting_level);
2404#endif // DEBUG
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002405}
2406
2407
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002408void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
2409 Code* interrupt_code,
2410 Code* replacement_code) {
2411 // Iterate over the back edge table and revert the patched interrupt calls.
2412 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
2413 ASSERT(unoptimized_code->back_edges_patched_for_osr());
2414 int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
2415 Address back_edge_cursor = unoptimized_code->instruction_start() +
2416 unoptimized_code->back_edge_table_offset();
2417 uint32_t table_length = Memory::uint32_at(back_edge_cursor);
2418 back_edge_cursor += kIntSize;
2419 for (uint32_t i = 0; i < table_length; ++i) {
2420 uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
2421 if (loop_depth <= loop_nesting_level) {
2422 uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
2423 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
2424 RevertInterruptCodeAt(unoptimized_code,
2425 pc_after,
2426 interrupt_code,
2427 replacement_code);
2428 }
2429 back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
2430 }
2431 unoptimized_code->set_back_edges_patched_for_osr(false);
2432#ifdef DEBUG
2433 // Assert that none of the back edges are patched anymore.
2434 Deoptimizer::VerifyInterruptCode(
2435 unoptimized_code, interrupt_code, replacement_code, -1);
2436#endif // DEBUG
2437}
2438
2439
2440#ifdef DEBUG
2441void Deoptimizer::VerifyInterruptCode(Code* unoptimized_code,
2442 Code* interrupt_code,
2443 Code* replacement_code,
2444 int loop_nesting_level) {
2445 CHECK(unoptimized_code->kind() == Code::FUNCTION);
2446 Address back_edge_cursor = unoptimized_code->instruction_start() +
2447 unoptimized_code->back_edge_table_offset();
2448 uint32_t table_length = Memory::uint32_at(back_edge_cursor);
2449 back_edge_cursor += kIntSize;
2450 for (uint32_t i = 0; i < table_length; ++i) {
2451 uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
2452 CHECK_LE(loop_depth, Code::kMaxLoopNestingMarker);
2453 // Assert that all back edges for shallower loops (and only those)
2454 // have already been patched.
2455 uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
2456 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
2457 CHECK_EQ((loop_depth <= loop_nesting_level),
2458 InterruptCodeIsPatched(unoptimized_code,
2459 pc_after,
2460 interrupt_code,
2461 replacement_code));
2462 back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
2463 }
2464}
2465#endif // DEBUG
2466
2467
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002468unsigned Deoptimizer::ComputeInputFrameSize() const {
2469 unsigned fixed_size = ComputeFixedSize(function_);
2470 // The fp-to-sp delta already takes the context and the function
2471 // into account so we have to avoid double counting them (-2).
2472 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
2473#ifdef DEBUG
2474 if (bailout_type_ == OSR) {
2475 // TODO(kasperl): It would be nice if we could verify that the
2476 // size matches with the stack height we can compute based on the
2477 // environment at the OSR entry. The code for that his built into
2478 // the DoComputeOsrOutputFrame function for now.
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002479 } else if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002480 unsigned stack_slots = compiled_code_->stack_slots();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002481 unsigned outgoing_size = ComputeOutgoingArgumentSize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002482 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
2483 }
2484#endif
2485 return result;
2486}
2487
2488
2489unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
2490 // The fixed part of the frame consists of the return address, frame
2491 // pointer, function, context, and all the incoming arguments.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002492 return ComputeIncomingArgumentSize(function) +
2493 StandardFrameConstants::kFixedFrameSize;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002494}
2495
2496
2497unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
2498 // The incoming arguments is the values for formal parameters and
2499 // the receiver. Every slot contains a pointer.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002500 if (function->IsSmi()) {
2501 ASSERT(Smi::cast(function) == Smi::FromInt(StackFrame::STUB));
2502 return 0;
2503 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002504 unsigned arguments = function->shared()->formal_parameter_count() + 1;
2505 return arguments * kPointerSize;
2506}
2507
2508
2509unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
2510 DeoptimizationInputData* data = DeoptimizationInputData::cast(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002511 compiled_code_->deoptimization_data());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002512 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
2513 return height * kPointerSize;
2514}
2515
2516
2517Object* Deoptimizer::ComputeLiteral(int index) const {
2518 DeoptimizationInputData* data = DeoptimizationInputData::cast(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002519 compiled_code_->deoptimization_data());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002520 FixedArray* literals = data->LiteralArray();
2521 return literals->get(index);
2522}
2523
2524
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002525void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) {
2526 ObjectMaterializationDescriptor object_desc(
2527 reinterpret_cast<Address>(slot_address), length);
2528 deferred_objects_.Add(object_desc);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002529}
2530
2531
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002532void Deoptimizer::AddObjectTaggedValue(intptr_t value) {
2533 deferred_objects_tagged_values_.Add(reinterpret_cast<Object*>(value));
2534 deferred_objects_double_values_.Add(isolate()->heap()->nan_value()->value());
2535}
2536
2537
2538void Deoptimizer::AddObjectDoubleValue(double value) {
2539 deferred_objects_tagged_values_.Add(isolate()->heap()->the_hole_value());
2540 deferred_objects_double_values_.Add(value);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002541}
2542
2543
2544void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002545 HeapNumberMaterializationDescriptor value_desc(
2546 reinterpret_cast<Address>(slot_address), value);
2547 deferred_heap_numbers_.Add(value_desc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002548}
2549
2550
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002551void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
2552 BailoutType type,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002553 int max_entry_id) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002554 // We cannot run this if the serializer is enabled because this will
2555 // cause us to emit relocation information for the external
2556 // references. This is fine because the deoptimizer's code section
2557 // isn't meant to be serialized at all.
danno@chromium.orgaefd6072013-05-14 14:11:47 +00002558 ASSERT(type == EAGER || type == SOFT || type == LAZY);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002559 DeoptimizerData* data = isolate->deoptimizer_data();
danno@chromium.orgaefd6072013-05-14 14:11:47 +00002560 int entry_count = data->deopt_entry_code_entries_[type];
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002561 if (max_entry_id < entry_count) return;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002562 entry_count = Max(entry_count, Deoptimizer::kMinNumberOfEntries);
2563 while (max_entry_id >= entry_count) entry_count *= 2;
2564 ASSERT(entry_count <= Deoptimizer::kMaxNumberOfEntries);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002565
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002566 MacroAssembler masm(isolate, NULL, 16 * KB);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002567 masm.set_emit_debug_code(false);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002568 GenerateDeoptimizationEntries(&masm, entry_count, type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002569 CodeDesc desc;
2570 masm.GetCode(&desc);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002571 ASSERT(!RelocInfo::RequiresRelocation(desc));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002572
danno@chromium.orgaefd6072013-05-14 14:11:47 +00002573 MemoryChunk* chunk = data->deopt_entry_code_[type];
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00002574 ASSERT(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
2575 desc.instr_size);
2576 chunk->CommitArea(desc.instr_size);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002577 CopyBytes(chunk->area_start(), desc.buffer,
2578 static_cast<size_t>(desc.instr_size));
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00002579 CPU::FlushICache(chunk->area_start(), desc.instr_size);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002580
danno@chromium.orgaefd6072013-05-14 14:11:47 +00002581 data->deopt_entry_code_entries_[type] = entry_count;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002582}
2583
2584
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002585void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function,
2586 Code* code) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002587 SharedFunctionInfo* shared = function->shared();
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00002588 Object* undefined = function->GetHeap()->undefined_value();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002589 Object* current = function;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002590
2591 while (current != undefined) {
2592 JSFunction* func = JSFunction::cast(current);
2593 current = func->next_function_link();
2594 func->set_code(shared->code());
2595 func->set_next_function_link(undefined);
2596 }
2597}
2598
2599
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002600FrameDescription::FrameDescription(uint32_t frame_size,
2601 JSFunction* function)
2602 : frame_size_(frame_size),
2603 function_(function),
2604 top_(kZapUint32),
2605 pc_(kZapUint32),
ulan@chromium.org967e2702012-02-28 09:49:15 +00002606 fp_(kZapUint32),
2607 context_(kZapUint32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002608 // Zap all the registers.
2609 for (int r = 0; r < Register::kNumRegisters; r++) {
2610 SetRegister(r, kZapUint32);
2611 }
2612
2613 // Zap all the slots.
2614 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
2615 SetFrameSlot(o, kZapUint32);
2616 }
2617}
2618
2619
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002620int FrameDescription::ComputeFixedSize() {
2621 return StandardFrameConstants::kFixedFrameSize +
2622 (ComputeParametersCount() + 1) * kPointerSize;
2623}
2624
2625
2626unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002627 if (slot_index >= 0) {
2628 // Local or spill slots. Skip the fixed part of the frame
2629 // including all arguments.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002630 unsigned base = GetFrameSize() - ComputeFixedSize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002631 return base - ((slot_index + 1) * kPointerSize);
2632 } else {
2633 // Incoming parameter.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002634 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
2635 unsigned base = GetFrameSize() - arg_size;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002636 return base - ((slot_index + 1) * kPointerSize);
2637 }
2638}
2639
2640
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002641int FrameDescription::ComputeParametersCount() {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002642 switch (type_) {
2643 case StackFrame::JAVA_SCRIPT:
2644 return function_->shared()->formal_parameter_count();
2645 case StackFrame::ARGUMENTS_ADAPTOR: {
2646 // Last slot contains number of incomming arguments as a smi.
2647 // Can't use GetExpression(0) because it would cause infinite recursion.
2648 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value();
2649 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00002650 case StackFrame::STUB:
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002651 return -1; // Minus receiver.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002652 default:
2653 UNREACHABLE();
2654 return 0;
2655 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002656}
2657
2658
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002659Object* FrameDescription::GetParameter(int index) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002660 ASSERT(index >= 0);
2661 ASSERT(index < ComputeParametersCount());
2662 // The slot indexes for incoming arguments are negative.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002663 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002664 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
2665}
2666
2667
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002668unsigned FrameDescription::GetExpressionCount() {
2669 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
2670 unsigned size = GetFrameSize() - ComputeFixedSize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002671 return size / kPointerSize;
2672}
2673
2674
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002675Object* FrameDescription::GetExpression(int index) {
2676 ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_);
2677 unsigned offset = GetOffsetFromSlotIndex(index);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002678 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
2679}
2680
2681
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002682void TranslationBuffer::Add(int32_t value, Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002683 // Encode the sign bit in the least significant bit.
2684 bool is_negative = (value < 0);
2685 uint32_t bits = ((is_negative ? -value : value) << 1) |
2686 static_cast<int32_t>(is_negative);
2687 // Encode the individual bytes using the least significant bit of
2688 // each byte to indicate whether or not more bytes follow.
2689 do {
2690 uint32_t next = bits >> 7;
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002691 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002692 bits = next;
2693 } while (bits != 0);
2694}
2695
2696
2697int32_t TranslationIterator::Next() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002698 // Run through the bytes until we reach one with a least significant
2699 // bit of zero (marks the end).
2700 uint32_t bits = 0;
2701 for (int i = 0; true; i += 7) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002702 ASSERT(HasNext());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002703 uint8_t next = buffer_->get(index_++);
2704 bits |= (next >> 1) << i;
2705 if ((next & 1) == 0) break;
2706 }
2707 // The bits encode the sign in the least significant bit.
2708 bool is_negative = (bits & 1) == 1;
2709 int32_t result = bits >> 1;
2710 return is_negative ? -result : result;
2711}
2712
2713
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00002714Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002715 int length = contents_.length();
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00002716 Handle<ByteArray> result = factory->NewByteArray(length, TENURED);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002717 OS::MemCopy(
2718 result->GetDataStartAddress(), contents_.ToVector().start(), length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002719 return result;
2720}
2721
2722
ulan@chromium.org967e2702012-02-28 09:49:15 +00002723void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002724 buffer_->Add(CONSTRUCT_STUB_FRAME, zone());
2725 buffer_->Add(literal_id, zone());
2726 buffer_->Add(height, zone());
ulan@chromium.org967e2702012-02-28 09:49:15 +00002727}
2728
2729
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002730void Translation::BeginGetterStubFrame(int literal_id) {
2731 buffer_->Add(GETTER_STUB_FRAME, zone());
2732 buffer_->Add(literal_id, zone());
2733}
2734
2735
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002736void Translation::BeginSetterStubFrame(int literal_id) {
2737 buffer_->Add(SETTER_STUB_FRAME, zone());
2738 buffer_->Add(literal_id, zone());
2739}
2740
2741
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002742void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002743 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone());
2744 buffer_->Add(literal_id, zone());
2745 buffer_->Add(height, zone());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002746}
2747
2748
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002749void Translation::BeginJSFrame(BailoutId node_id,
2750 int literal_id,
2751 unsigned height) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002752 buffer_->Add(JS_FRAME, zone());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002753 buffer_->Add(node_id.ToInt(), zone());
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002754 buffer_->Add(literal_id, zone());
2755 buffer_->Add(height, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002756}
2757
2758
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002759void Translation::BeginCompiledStubFrame() {
2760 buffer_->Add(COMPILED_STUB_FRAME, zone());
2761}
2762
2763
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002764void Translation::BeginArgumentsObject(int args_length) {
2765 buffer_->Add(ARGUMENTS_OBJECT, zone());
2766 buffer_->Add(args_length, zone());
2767}
2768
2769
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002770void Translation::StoreRegister(Register reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002771 buffer_->Add(REGISTER, zone());
2772 buffer_->Add(reg.code(), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002773}
2774
2775
2776void Translation::StoreInt32Register(Register reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002777 buffer_->Add(INT32_REGISTER, zone());
2778 buffer_->Add(reg.code(), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002779}
2780
2781
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002782void Translation::StoreUint32Register(Register reg) {
2783 buffer_->Add(UINT32_REGISTER, zone());
2784 buffer_->Add(reg.code(), zone());
2785}
2786
2787
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002788void Translation::StoreDoubleRegister(DoubleRegister reg) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002789 buffer_->Add(DOUBLE_REGISTER, zone());
2790 buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002791}
2792
2793
2794void Translation::StoreStackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002795 buffer_->Add(STACK_SLOT, zone());
2796 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002797}
2798
2799
2800void Translation::StoreInt32StackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002801 buffer_->Add(INT32_STACK_SLOT, zone());
2802 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002803}
2804
2805
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002806void Translation::StoreUint32StackSlot(int index) {
2807 buffer_->Add(UINT32_STACK_SLOT, zone());
2808 buffer_->Add(index, zone());
2809}
2810
2811
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002812void Translation::StoreDoubleStackSlot(int index) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002813 buffer_->Add(DOUBLE_STACK_SLOT, zone());
2814 buffer_->Add(index, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002815}
2816
2817
2818void Translation::StoreLiteral(int literal_id) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002819 buffer_->Add(LITERAL, zone());
2820 buffer_->Add(literal_id, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002821}
2822
2823
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002824void Translation::MarkDuplicate() {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002825 buffer_->Add(DUPLICATE, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002826}
2827
2828
2829int Translation::NumberOfOperandsFor(Opcode opcode) {
2830 switch (opcode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002831 case DUPLICATE:
2832 return 0;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002833 case GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002834 case SETTER_STUB_FRAME:
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002835 case ARGUMENTS_OBJECT:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002836 case REGISTER:
2837 case INT32_REGISTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002838 case UINT32_REGISTER:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002839 case DOUBLE_REGISTER:
2840 case STACK_SLOT:
2841 case INT32_STACK_SLOT:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002842 case UINT32_STACK_SLOT:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002843 case DOUBLE_STACK_SLOT:
2844 case LITERAL:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002845 case COMPILED_STUB_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002846 return 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002847 case BEGIN:
2848 case ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00002849 case CONSTRUCT_STUB_FRAME:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002850 return 2;
2851 case JS_FRAME:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002852 return 3;
2853 }
2854 UNREACHABLE();
2855 return -1;
2856}
2857
2858
whesse@chromium.org7b260152011-06-20 15:33:18 +00002859#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002860
2861const char* Translation::StringFor(Opcode opcode) {
2862 switch (opcode) {
2863 case BEGIN:
2864 return "BEGIN";
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002865 case JS_FRAME:
2866 return "JS_FRAME";
2867 case ARGUMENTS_ADAPTOR_FRAME:
2868 return "ARGUMENTS_ADAPTOR_FRAME";
ulan@chromium.org967e2702012-02-28 09:49:15 +00002869 case CONSTRUCT_STUB_FRAME:
2870 return "CONSTRUCT_STUB_FRAME";
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002871 case GETTER_STUB_FRAME:
2872 return "GETTER_STUB_FRAME";
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002873 case SETTER_STUB_FRAME:
2874 return "SETTER_STUB_FRAME";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002875 case COMPILED_STUB_FRAME:
2876 return "COMPILED_STUB_FRAME";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002877 case REGISTER:
2878 return "REGISTER";
2879 case INT32_REGISTER:
2880 return "INT32_REGISTER";
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002881 case UINT32_REGISTER:
2882 return "UINT32_REGISTER";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002883 case DOUBLE_REGISTER:
2884 return "DOUBLE_REGISTER";
2885 case STACK_SLOT:
2886 return "STACK_SLOT";
2887 case INT32_STACK_SLOT:
2888 return "INT32_STACK_SLOT";
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002889 case UINT32_STACK_SLOT:
2890 return "UINT32_STACK_SLOT";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002891 case DOUBLE_STACK_SLOT:
2892 return "DOUBLE_STACK_SLOT";
2893 case LITERAL:
2894 return "LITERAL";
2895 case ARGUMENTS_OBJECT:
2896 return "ARGUMENTS_OBJECT";
2897 case DUPLICATE:
2898 return "DUPLICATE";
2899 }
2900 UNREACHABLE();
2901 return "";
2902}
2903
2904#endif
2905
2906
2907DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00002908 GlobalHandles* global_handles = code->GetIsolate()->global_handles();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002909 // Globalize the code object and make it weak.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002910 code_ = Handle<Code>::cast(global_handles->Create(code));
2911 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
2912 this,
2913 Deoptimizer::HandleWeakDeoptimizedCode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002914}
2915
2916
2917DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00002918 GlobalHandles* global_handles = code_->GetIsolate()->global_handles();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002920}
2921
2922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002923// We can't intermix stack decoding and allocations because
2924// deoptimization infrastracture is not GC safe.
2925// Thus we build a temporary structure in malloced space.
2926SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
2927 DeoptimizationInputData* data,
2928 JavaScriptFrame* frame) {
2929 Translation::Opcode opcode =
2930 static_cast<Translation::Opcode>(iterator->Next());
2931
2932 switch (opcode) {
2933 case Translation::BEGIN:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002934 case Translation::JS_FRAME:
2935 case Translation::ARGUMENTS_ADAPTOR_FRAME:
ulan@chromium.org967e2702012-02-28 09:49:15 +00002936 case Translation::CONSTRUCT_STUB_FRAME:
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002937 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002938 case Translation::SETTER_STUB_FRAME:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002939 // Peeled off before getting here.
2940 break;
2941
2942 case Translation::ARGUMENTS_OBJECT:
2943 // This can be only emitted for local slots not for argument slots.
2944 break;
2945
2946 case Translation::REGISTER:
2947 case Translation::INT32_REGISTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002948 case Translation::UINT32_REGISTER:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002949 case Translation::DOUBLE_REGISTER:
2950 case Translation::DUPLICATE:
2951 // We are at safepoint which corresponds to call. All registers are
2952 // saved by caller so there would be no live registers at this
2953 // point. Thus these translation commands should not be used.
2954 break;
2955
2956 case Translation::STACK_SLOT: {
2957 int slot_index = iterator->Next();
2958 Address slot_addr = SlotAddress(frame, slot_index);
2959 return SlotRef(slot_addr, SlotRef::TAGGED);
2960 }
2961
2962 case Translation::INT32_STACK_SLOT: {
2963 int slot_index = iterator->Next();
2964 Address slot_addr = SlotAddress(frame, slot_index);
2965 return SlotRef(slot_addr, SlotRef::INT32);
2966 }
2967
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002968 case Translation::UINT32_STACK_SLOT: {
2969 int slot_index = iterator->Next();
2970 Address slot_addr = SlotAddress(frame, slot_index);
2971 return SlotRef(slot_addr, SlotRef::UINT32);
2972 }
2973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002974 case Translation::DOUBLE_STACK_SLOT: {
2975 int slot_index = iterator->Next();
2976 Address slot_addr = SlotAddress(frame, slot_index);
2977 return SlotRef(slot_addr, SlotRef::DOUBLE);
2978 }
2979
2980 case Translation::LITERAL: {
2981 int literal_index = iterator->Next();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002982 return SlotRef(data->GetIsolate(),
2983 data->LiteralArray()->get(literal_index));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002984 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002985
2986 case Translation::COMPILED_STUB_FRAME:
2987 UNREACHABLE();
2988 break;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002989 }
2990
2991 UNREACHABLE();
2992 return SlotRef();
2993}
2994
2995
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002996void SlotRef::ComputeSlotsForArguments(Vector<SlotRef>* args_slots,
2997 TranslationIterator* it,
2998 DeoptimizationInputData* data,
2999 JavaScriptFrame* frame) {
3000 // Process the translation commands for the arguments.
3001
3002 // Skip the translation command for the receiver.
3003 it->Skip(Translation::NumberOfOperandsFor(
3004 static_cast<Translation::Opcode>(it->Next())));
3005
3006 // Compute slots for arguments.
3007 for (int i = 0; i < args_slots->length(); ++i) {
3008 (*args_slots)[i] = ComputeSlotForNextArgument(it, data, frame);
3009 }
3010}
3011
3012
3013Vector<SlotRef> SlotRef::ComputeSlotMappingForArguments(
3014 JavaScriptFrame* frame,
3015 int inlined_jsframe_index,
3016 int formal_parameter_count) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003017 DisallowHeapAllocation no_gc;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00003018 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003019 DeoptimizationInputData* data =
3020 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
3021 TranslationIterator it(data->TranslationByteArray(),
3022 data->TranslationIndex(deopt_index)->value());
3023 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
3024 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003025 it.Next(); // Drop frame count.
3026 int jsframe_count = it.Next();
3027 USE(jsframe_count);
3028 ASSERT(jsframe_count > inlined_jsframe_index);
3029 int jsframes_to_skip = inlined_jsframe_index;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003030 while (true) {
3031 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003032 if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) {
3033 if (jsframes_to_skip == 0) {
3034 ASSERT(Translation::NumberOfOperandsFor(opcode) == 2);
3035
3036 it.Skip(1); // literal id
3037 int height = it.Next();
3038
3039 // We reached the arguments adaptor frame corresponding to the
3040 // inlined function in question. Number of arguments is height - 1.
3041 Vector<SlotRef> args_slots =
3042 Vector<SlotRef>::New(height - 1); // Minus receiver.
3043 ComputeSlotsForArguments(&args_slots, &it, data, frame);
3044 return args_slots;
3045 }
3046 } else if (opcode == Translation::JS_FRAME) {
3047 if (jsframes_to_skip == 0) {
3048 // Skip over operands to advance to the next opcode.
3049 it.Skip(Translation::NumberOfOperandsFor(opcode));
3050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003051 // We reached the frame corresponding to the inlined function
3052 // in question. Process the translation commands for the
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003053 // arguments. Number of arguments is equal to the number of
3054 // format parameter count.
3055 Vector<SlotRef> args_slots =
3056 Vector<SlotRef>::New(formal_parameter_count);
3057 ComputeSlotsForArguments(&args_slots, &it, data, frame);
3058 return args_slots;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003059 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003060 jsframes_to_skip--;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003061 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003062
3063 // Skip over operands to advance to the next opcode.
3064 it.Skip(Translation::NumberOfOperandsFor(opcode));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003065 }
3066
3067 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003068 return Vector<SlotRef>();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003069}
3070
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003071#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003072
ulan@chromium.org967e2702012-02-28 09:49:15 +00003073DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
3074 int frame_index,
3075 bool has_arguments_adaptor,
3076 bool has_construct_stub) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003077 FrameDescription* output_frame = deoptimizer->output_[frame_index];
ulan@chromium.org967e2702012-02-28 09:49:15 +00003078 function_ = output_frame->GetFunction();
3079 has_construct_stub_ = has_construct_stub;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003080 expression_count_ = output_frame->GetExpressionCount();
3081 expression_stack_ = new Object*[expression_count_];
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003082 // Get the source position using the unoptimized code.
3083 Address pc = reinterpret_cast<Address>(output_frame->GetPc());
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00003084 Code* code = Code::cast(deoptimizer->isolate()->heap()->FindCodeObject(pc));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003085 source_position_ = code->SourcePosition(pc);
3086
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003087 for (int i = 0; i < expression_count_; i++) {
3088 SetExpression(i, output_frame->GetExpression(i));
3089 }
3090
3091 if (has_arguments_adaptor) {
3092 output_frame = deoptimizer->output_[frame_index - 1];
3093 ASSERT(output_frame->GetFrameType() == StackFrame::ARGUMENTS_ADAPTOR);
3094 }
3095
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003096 parameters_count_ = output_frame->ComputeParametersCount();
3097 parameters_ = new Object*[parameters_count_];
3098 for (int i = 0; i < parameters_count_; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003099 SetParameter(i, output_frame->GetParameter(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003100 }
3101}
3102
3103
3104DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003105 delete[] expression_stack_;
3106 delete[] parameters_;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003107}
3108
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003109
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003110void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003111 v->VisitPointer(BitCast<Object**>(&function_));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003112 v->VisitPointers(parameters_, parameters_ + parameters_count_);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003113 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
3114}
3115
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003116#endif // ENABLE_DEBUGGER_SUPPORT
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003117
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003118} } // namespace v8::internal