blob: 748f95eff7c275c5b467b25bdb087c0a1df1b557 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Ben Murdochb0fe1622011-05-05 13:52:32 +01004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +01006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/accessors.h"
8#include "src/codegen.h"
9#include "src/deoptimizer.h"
10#include "src/disasm.h"
11#include "src/full-codegen.h"
12#include "src/global-handles.h"
13#include "src/macro-assembler.h"
14#include "src/prettyprinter.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010015
16
17namespace v8 {
18namespace internal {
19
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020static MemoryChunk* AllocateCodeChunk(MemoryAllocator* allocator) {
21 return allocator->AllocateChunk(Deoptimizer::GetMaxDeoptTableSize(),
22 base::OS::CommitPageSize(),
23#if defined(__native_client__)
24 // The Native Client port of V8 uses an interpreter,
25 // so code pages don't need PROT_EXEC.
26 NOT_EXECUTABLE,
27#else
28 EXECUTABLE,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000029#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 NULL);
31}
32
33
34DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator)
35 : allocator_(allocator),
36 deoptimized_frame_info_(NULL),
37 current_(NULL) {
38 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
39 deopt_entry_code_entries_[i] = -1;
40 deopt_entry_code_[i] = AllocateCodeChunk(allocator);
41 }
Steve Block44f0eee2011-05-26 01:26:41 +010042}
Ben Murdochb0fe1622011-05-05 13:52:32 +010043
44
Steve Block44f0eee2011-05-26 01:26:41 +010045DeoptimizerData::~DeoptimizerData() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
47 allocator_->Free(deopt_entry_code_[i]);
48 deopt_entry_code_[i] = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +010049 }
50}
51
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000052
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000053void DeoptimizerData::Iterate(ObjectVisitor* v) {
54 if (deoptimized_frame_info_ != NULL) {
55 deoptimized_frame_info_->Iterate(v);
56 }
57}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058
59
60Code* Deoptimizer::FindDeoptimizingCode(Address addr) {
61 if (function_->IsHeapObject()) {
62 // Search all deoptimizing code in the native context of the function.
63 Context* native_context = function_->context()->native_context();
64 Object* element = native_context->DeoptimizedCodeListHead();
65 while (!element->IsUndefined()) {
66 Code* code = Code::cast(element);
67 CHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
68 if (code->contains(addr)) return code;
69 element = code->next_code_link();
70 }
71 }
72 return NULL;
73}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000074
75
Ben Murdoch3ef787d2012-04-12 10:51:47 +010076// We rely on this function not causing a GC. It is called from generated code
77// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +010078Deoptimizer* Deoptimizer::New(JSFunction* function,
79 BailoutType type,
80 unsigned bailout_id,
81 Address from,
Steve Block44f0eee2011-05-26 01:26:41 +010082 int fp_to_sp_delta,
83 Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +010084 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
85 function,
86 type,
87 bailout_id,
88 from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000089 fp_to_sp_delta,
90 NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091 CHECK(isolate->deoptimizer_data()->current_ == NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010092 isolate->deoptimizer_data()->current_ = deoptimizer;
Ben Murdochb0fe1622011-05-05 13:52:32 +010093 return deoptimizer;
94}
95
96
Ben Murdochb8a8cc12014-11-26 15:28:44 +000097// No larger than 2K on all platforms
98static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
99
100
101size_t Deoptimizer::GetMaxDeoptTableSize() {
102 int entries_size =
103 Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
104 int commit_page_size = static_cast<int>(base::OS::CommitPageSize());
105 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
106 commit_page_size) + 1;
107 return static_cast<size_t>(commit_page_size * page_count);
108}
109
110
Steve Block44f0eee2011-05-26 01:26:41 +0100111Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100112 Deoptimizer* result = isolate->deoptimizer_data()->current_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 CHECK_NE(result, NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100114 result->DeleteFrameDescriptions();
Steve Block44f0eee2011-05-26 01:26:41 +0100115 isolate->deoptimizer_data()->current_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100116 return result;
117}
118
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100119
120int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) {
121 if (jsframe_index == 0) return 0;
122
123 int frame_index = 0;
124 while (jsframe_index >= 0) {
125 FrameDescription* frame = output_[frame_index];
126 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) {
127 jsframe_index--;
128 }
129 frame_index++;
130 }
131
132 return frame_index - 1;
133}
134
135
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000136DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
137 JavaScriptFrame* frame,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100138 int jsframe_index,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000139 Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 CHECK(frame->is_optimized());
141 CHECK(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000142
143 // Get the function and code from the frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 JSFunction* function = frame->function();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000145 Code* code = frame->LookupCode();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000146
147 // Locate the deoptimization point in the code. As we are at a call the
148 // return address must be at a place in the code with deoptimization support.
Ben Murdoch2b4ba112012-01-20 14:57:15 +0000149 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
150 int deoptimization_index = safepoint_entry.deoptimization_index();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151 CHECK_NE(deoptimization_index, Safepoint::kNoDeoptimizationIndex);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000152
153 // Always use the actual stack slots when calculating the fp to sp
154 // delta adding two for the function and context.
155 unsigned stack_slots = code->stack_slots();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156 unsigned fp_to_sp_delta = (stack_slots * kPointerSize) +
157 StandardFrameConstants::kFixedFrameSizeFromFp;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000158
159 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
160 function,
161 Deoptimizer::DEBUGGER,
162 deoptimization_index,
163 frame->pc(),
164 fp_to_sp_delta,
165 code);
166 Address tos = frame->fp() - fp_to_sp_delta;
167 deoptimizer->FillInputFrame(tos, frame);
168
169 // Calculate the output frames.
170 Deoptimizer::ComputeOutputFrames(deoptimizer);
171
172 // Create the GC safe output frame information and register it for GC
173 // handling.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 CHECK_LT(jsframe_index, deoptimizer->jsframe_count());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100175
176 // Convert JS frame index into frame index.
177 int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index);
178
179 bool has_arguments_adaptor =
180 frame_index > 0 &&
181 deoptimizer->output_[frame_index - 1]->GetFrameType() ==
182 StackFrame::ARGUMENTS_ADAPTOR;
183
184 int construct_offset = has_arguments_adaptor ? 2 : 1;
185 bool has_construct_stub =
186 frame_index >= construct_offset &&
187 deoptimizer->output_[frame_index - construct_offset]->GetFrameType() ==
188 StackFrame::CONSTRUCT;
189
190 DeoptimizedFrameInfo* info = new DeoptimizedFrameInfo(deoptimizer,
191 frame_index,
192 has_arguments_adaptor,
193 has_construct_stub);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000194 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
195
196 // Get the "simulated" top and size for the requested frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100197 FrameDescription* parameters_frame =
198 deoptimizer->output_[
199 has_arguments_adaptor ? (frame_index - 1) : frame_index];
200
201 uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize;
202 Address parameters_top = reinterpret_cast<Address>(
203 parameters_frame->GetTop() + (parameters_frame->GetFrameSize() -
204 parameters_size));
205
206 uint32_t expressions_size = info->expression_count() * kPointerSize;
207 Address expressions_top = reinterpret_cast<Address>(
208 deoptimizer->output_[frame_index]->GetTop());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000209
210 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
211 deoptimizer->DeleteFrameDescriptions();
212
213 // Allocate a heap number for the doubles belonging to this frame.
214 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100215 parameters_top, parameters_size, expressions_top, expressions_size, info);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000216
217 // Finished using the deoptimizer instance.
218 delete deoptimizer;
219
220 return info;
221}
222
223
224void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
225 Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226 CHECK_EQ(isolate->deoptimizer_data()->deoptimized_frame_info_, info);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000227 delete info;
228 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
229}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000230
Ben Murdochb0fe1622011-05-05 13:52:32 +0100231
232void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
233 int count,
234 BailoutType type) {
235 TableEntryGenerator generator(masm, type, count);
236 generator.Generate();
237}
238
239
Ben Murdochb0fe1622011-05-05 13:52:32 +0100240void Deoptimizer::VisitAllOptimizedFunctionsForContext(
241 Context* context, OptimizedFunctionVisitor* visitor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100243
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 CHECK(context->IsNativeContext());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100245
246 visitor->EnterContext(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247
248 // Visit the list of optimized functions, removing elements that
249 // no longer refer to optimized code.
250 JSFunction* prev = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100251 Object* element = context->OptimizedFunctionsListHead();
252 while (!element->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000253 JSFunction* function = JSFunction::cast(element);
254 Object* next = function->next_function_link();
255 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION ||
256 (visitor->VisitFunction(function),
257 function->code()->kind() != Code::OPTIMIZED_FUNCTION)) {
258 // The function no longer refers to optimized code, or the visitor
259 // changed the code to which it refers to no longer be optimized code.
260 // Remove the function from this list.
261 if (prev != NULL) {
262 prev->set_next_function_link(next);
263 } else {
264 context->SetOptimizedFunctionsListHead(next);
265 }
266 // The visitor should not alter the link directly.
267 CHECK_EQ(function->next_function_link(), next);
268 // Set the next function link to undefined to indicate it is no longer
269 // in the optimized functions list.
270 function->set_next_function_link(context->GetHeap()->undefined_value());
271 } else {
272 // The visitor should not alter the link directly.
273 CHECK_EQ(function->next_function_link(), next);
274 // preserve this element.
275 prev = function;
276 }
277 element = next;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100278 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279
Ben Murdochb0fe1622011-05-05 13:52:32 +0100280 visitor->LeaveContext(context);
281}
282
283
Ben Murdochb0fe1622011-05-05 13:52:32 +0100284void Deoptimizer::VisitAllOptimizedFunctions(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 Isolate* isolate,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100286 OptimizedFunctionVisitor* visitor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100288
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 // Run through the list of all native contexts.
290 Object* context = isolate->heap()->native_contexts_list();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100291 while (!context->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100293 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100294 }
295}
296
297
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298// Unlink functions referring to code marked for deoptimization, then move
299// marked code from the optimized code list to the deoptimized code list,
300// and patch code for lazy deopt.
301void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
302 DisallowHeapAllocation no_allocation;
303
304 // A "closure" that unlinks optimized code that is going to be
305 // deoptimized from the functions that refer to it.
306 class SelectedCodeUnlinker: public OptimizedFunctionVisitor {
307 public:
308 virtual void EnterContext(Context* context) { } // Don't care.
309 virtual void LeaveContext(Context* context) { } // Don't care.
310 virtual void VisitFunction(JSFunction* function) {
311 Code* code = function->code();
312 if (!code->marked_for_deoptimization()) return;
313
314 // Unlink this function and evict from optimized code map.
315 SharedFunctionInfo* shared = function->shared();
316 function->set_code(shared->code());
317
318 if (FLAG_trace_deopt) {
319 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
320 PrintF(scope.file(), "[deoptimizer unlinked: ");
321 function->PrintName(scope.file());
322 PrintF(scope.file(),
323 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
324 }
325 }
326 };
327
328 // Unlink all functions that refer to marked code.
329 SelectedCodeUnlinker unlinker;
330 VisitAllOptimizedFunctionsForContext(context, &unlinker);
331
332 Isolate* isolate = context->GetHeap()->isolate();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100333#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334 Code* topmost_optimized_code = NULL;
335 bool safe_to_deopt_topmost_optimized_code = false;
336 // Make sure all activations of optimized code can deopt at their current PC.
337 // The topmost optimized code has special handling because it cannot be
338 // deoptimized due to weak object dependency.
339 for (StackFrameIterator it(isolate, isolate->thread_local_top());
340 !it.done(); it.Advance()) {
341 StackFrame::Type type = it.frame()->type();
342 if (type == StackFrame::OPTIMIZED) {
343 Code* code = it.frame()->LookupCode();
344 if (FLAG_trace_deopt) {
345 JSFunction* function =
346 static_cast<OptimizedFrame*>(it.frame())->function();
347 CodeTracer::Scope scope(isolate->GetCodeTracer());
348 PrintF(scope.file(), "[deoptimizer found activation of function: ");
349 function->PrintName(scope.file());
350 PrintF(scope.file(),
351 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
352 }
353 SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
354 int deopt_index = safepoint.deoptimization_index();
355 // Turbofan deopt is checked when we are patching addresses on stack.
356 bool turbofanned = code->is_turbofanned() && !FLAG_turbo_deoptimization;
357 bool safe_to_deopt =
358 deopt_index != Safepoint::kNoDeoptimizationIndex || turbofanned;
359 CHECK(topmost_optimized_code == NULL || safe_to_deopt || turbofanned);
360 if (topmost_optimized_code == NULL) {
361 topmost_optimized_code = code;
362 safe_to_deopt_topmost_optimized_code = safe_to_deopt;
363 }
364 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100365 }
366#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000367
368 // Move marked code from the optimized code list to the deoptimized
369 // code list, collecting them into a ZoneList.
370 Zone zone(isolate);
371 ZoneList<Code*> codes(10, &zone);
372
373 // Walk over all optimized code objects in this native context.
374 Code* prev = NULL;
375 Object* element = context->OptimizedCodeListHead();
376 while (!element->IsUndefined()) {
377 Code* code = Code::cast(element);
378 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
379 Object* next = code->next_code_link();
380
381 if (code->marked_for_deoptimization() &&
382 (!code->is_turbofanned() || FLAG_turbo_deoptimization)) {
383 // Put the code into the list for later patching.
384 codes.Add(code, &zone);
385
386 if (prev != NULL) {
387 // Skip this code in the optimized code list.
388 prev->set_next_code_link(next);
389 } else {
390 // There was no previous node, the next node is the new head.
391 context->SetOptimizedCodeListHead(next);
392 }
393
394 // Move the code to the _deoptimized_ code list.
395 code->set_next_code_link(context->DeoptimizedCodeListHead());
396 context->SetDeoptimizedCodeListHead(code);
397 } else {
398 // Not marked; preserve this element.
399 prev = code;
400 }
401 element = next;
402 }
403
404 // TODO(titzer): we need a handle scope only because of the macro assembler,
405 // which is only used in EnsureCodeForDeoptimizationEntry.
406 HandleScope scope(isolate);
407
408 // Now patch all the codes for deoptimization.
409 for (int i = 0; i < codes.length(); i++) {
410#ifdef DEBUG
411 if (codes[i] == topmost_optimized_code) {
412 DCHECK(safe_to_deopt_topmost_optimized_code);
413 }
414#endif
415 // It is finally time to die, code object.
416
417 // Remove the code from optimized code map.
418 DeoptimizationInputData* deopt_data =
419 DeoptimizationInputData::cast(codes[i]->deoptimization_data());
420 SharedFunctionInfo* shared =
421 SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
422 shared->EvictFromOptimizedCodeMap(codes[i], "deoptimized code");
423
424 // Do platform-specific patching to force any activations to lazy deopt.
425 if (!codes[i]->is_turbofanned() || FLAG_turbo_deoptimization) {
426 PatchCodeForDeoptimization(isolate, codes[i]);
427
428 // We might be in the middle of incremental marking with compaction.
429 // Tell collector to treat this code object in a special way and
430 // ignore all slots that might have been recorded on it.
431 isolate->heap()->mark_compact_collector()->InvalidateCode(codes[i]);
432 }
433 }
434}
435
436
437void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
438 if (FLAG_trace_deopt) {
439 CodeTracer::Scope scope(isolate->GetCodeTracer());
440 PrintF(scope.file(), "[deoptimize all code in all contexts]\n");
441 }
442 DisallowHeapAllocation no_allocation;
443 // For all contexts, mark all code, then deoptimize.
444 Object* context = isolate->heap()->native_contexts_list();
445 while (!context->IsUndefined()) {
446 Context* native_context = Context::cast(context);
447 MarkAllCodeForContext(native_context);
448 DeoptimizeMarkedCodeForContext(native_context);
449 context = native_context->get(Context::NEXT_CONTEXT_LINK);
450 }
451}
452
453
454void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) {
455 if (FLAG_trace_deopt) {
456 CodeTracer::Scope scope(isolate->GetCodeTracer());
457 PrintF(scope.file(), "[deoptimize marked code in all contexts]\n");
458 }
459 DisallowHeapAllocation no_allocation;
460 // For all contexts, deoptimize code already marked.
461 Object* context = isolate->heap()->native_contexts_list();
462 while (!context->IsUndefined()) {
463 Context* native_context = Context::cast(context);
464 DeoptimizeMarkedCodeForContext(native_context);
465 context = native_context->get(Context::NEXT_CONTEXT_LINK);
466 }
467}
468
469
470void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
471 if (FLAG_trace_deopt) {
472 CodeTracer::Scope scope(object->GetHeap()->isolate()->GetCodeTracer());
473 PrintF(scope.file(), "[deoptimize global object @ 0x%08" V8PRIxPTR "]\n",
474 reinterpret_cast<intptr_t>(object));
475 }
476 if (object->IsJSGlobalProxy()) {
477 PrototypeIterator iter(object->GetIsolate(), object);
478 // TODO(verwaest): This CHECK will be hit if the global proxy is detached.
479 CHECK(iter.GetCurrent()->IsJSGlobalObject());
480 Context* native_context =
481 GlobalObject::cast(iter.GetCurrent())->native_context();
482 MarkAllCodeForContext(native_context);
483 DeoptimizeMarkedCodeForContext(native_context);
484 } else if (object->IsGlobalObject()) {
485 Context* native_context = GlobalObject::cast(object)->native_context();
486 MarkAllCodeForContext(native_context);
487 DeoptimizeMarkedCodeForContext(native_context);
488 }
489}
490
491
492void Deoptimizer::MarkAllCodeForContext(Context* context) {
493 Object* element = context->OptimizedCodeListHead();
494 while (!element->IsUndefined()) {
495 Code* code = Code::cast(element);
496 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
497 code->set_marked_for_deoptimization(true);
498 element = code->next_code_link();
499 }
500}
501
502
503void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
504 Code* code = function->code();
505 if (code->kind() == Code::OPTIMIZED_FUNCTION) {
506 // Mark the code for deoptimization and unlink any functions that also
507 // refer to that code. The code cannot be shared across native contexts,
508 // so we only need to search one.
509 code->set_marked_for_deoptimization(true);
510 DeoptimizeMarkedCodeForContext(function->context()->native_context());
511 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100512}
513
514
Ben Murdoch8b112d22011-06-08 16:22:53 +0100515void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100516 deoptimizer->DoComputeOutputFrames();
517}
518
519
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000520bool Deoptimizer::TraceEnabledFor(BailoutType deopt_type,
521 StackFrame::Type frame_type) {
522 switch (deopt_type) {
523 case EAGER:
524 case SOFT:
525 case LAZY:
526 case DEBUGGER:
527 return (frame_type == StackFrame::STUB)
528 ? FLAG_trace_stub_failures
529 : FLAG_trace_deopt;
530 }
531 FATAL("Unsupported deopt type");
532 return false;
533}
534
535
536const char* Deoptimizer::MessageFor(BailoutType type) {
537 switch (type) {
538 case EAGER: return "eager";
539 case SOFT: return "soft";
540 case LAZY: return "lazy";
541 case DEBUGGER: return "debugger";
542 }
543 FATAL("Unsupported deopt type");
544 return NULL;
545}
546
547
Steve Block44f0eee2011-05-26 01:26:41 +0100548Deoptimizer::Deoptimizer(Isolate* isolate,
549 JSFunction* function,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100550 BailoutType type,
551 unsigned bailout_id,
552 Address from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000553 int fp_to_sp_delta,
554 Code* optimized_code)
Steve Block44f0eee2011-05-26 01:26:41 +0100555 : isolate_(isolate),
556 function_(function),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100557 bailout_id_(bailout_id),
558 bailout_type_(type),
559 from_(from),
560 fp_to_sp_delta_(fp_to_sp_delta),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 has_alignment_padding_(0),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000562 input_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100563 output_count_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100564 jsframe_count_(0),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100565 output_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 deferred_objects_tagged_values_(0),
567 deferred_objects_double_values_(0),
568 deferred_objects_(0),
569 deferred_heap_numbers_(0),
570 jsframe_functions_(0),
571 jsframe_has_adapted_arguments_(0),
572 materialized_values_(NULL),
573 materialized_objects_(NULL),
574 materialization_value_index_(0),
575 materialization_object_index_(0),
576 trace_scope_(NULL) {
577 // For COMPILED_STUBs called from builtins, the function pointer is a SMI
578 // indicating an internal frame.
579 if (function->IsSmi()) {
580 function = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100581 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 DCHECK(from != NULL);
583 if (function != NULL && function->IsOptimized()) {
584 function->shared()->increment_deopt_count();
585 if (bailout_type_ == Deoptimizer::SOFT) {
586 isolate->counters()->soft_deopts_executed()->Increment();
587 // Soft deopts shouldn't count against the overall re-optimization count
588 // that can eventually lead to disabling optimization for a function.
589 int opt_count = function->shared()->opt_count();
590 if (opt_count > 0) opt_count--;
591 function->shared()->set_opt_count(opt_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100592 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100593 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 compiled_code_ = FindOptimizedCode(function, optimized_code);
595
596#if DEBUG
597 DCHECK(compiled_code_ != NULL);
598 if (type == EAGER || type == SOFT || type == LAZY) {
599 DCHECK(compiled_code_->kind() != Code::FUNCTION);
600 }
601#endif
602
603 StackFrame::Type frame_type = function == NULL
604 ? StackFrame::STUB
605 : StackFrame::JAVA_SCRIPT;
606 trace_scope_ = TraceEnabledFor(type, frame_type) ?
607 new CodeTracer::Scope(isolate->GetCodeTracer()) : NULL;
608#ifdef DEBUG
609 CHECK(AllowHeapAllocation::IsAllowed());
610 disallow_heap_allocation_ = new DisallowHeapAllocation();
611#endif // DEBUG
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612 unsigned size = ComputeInputFrameSize();
613 input_ = new(size) FrameDescription(size, function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000614 input_->SetFrameType(frame_type);
615}
616
617
618Code* Deoptimizer::FindOptimizedCode(JSFunction* function,
619 Code* optimized_code) {
620 switch (bailout_type_) {
621 case Deoptimizer::SOFT:
622 case Deoptimizer::EAGER:
623 case Deoptimizer::LAZY: {
624 Code* compiled_code = FindDeoptimizingCode(from_);
625 return (compiled_code == NULL)
626 ? static_cast<Code*>(isolate_->FindCodeObject(from_))
627 : compiled_code;
628 }
629 case Deoptimizer::DEBUGGER:
630 DCHECK(optimized_code->contains(from_));
631 return optimized_code;
632 }
633 FATAL("Could not find code for optimized function");
634 return NULL;
635}
636
637
638void Deoptimizer::PrintFunctionName() {
639 if (function_->IsJSFunction()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400640 function_->ShortPrint(trace_scope_->file());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000641 } else {
642 PrintF(trace_scope_->file(),
643 "%s", Code::Kind2String(compiled_code_->kind()));
644 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100645}
646
647
648Deoptimizer::~Deoptimizer() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000649 DCHECK(input_ == NULL && output_ == NULL);
650 DCHECK(disallow_heap_allocation_ == NULL);
651 delete trace_scope_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100652}
653
654
655void Deoptimizer::DeleteFrameDescriptions() {
656 delete input_;
657 for (int i = 0; i < output_count_; ++i) {
658 if (output_[i] != input_) delete output_[i];
659 }
660 delete[] output_;
661 input_ = NULL;
662 output_ = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000663#ifdef DEBUG
664 CHECK(!AllowHeapAllocation::IsAllowed());
665 CHECK(disallow_heap_allocation_ != NULL);
666 delete disallow_heap_allocation_;
667 disallow_heap_allocation_ = NULL;
668#endif // DEBUG
Ben Murdochb0fe1622011-05-05 13:52:32 +0100669}
670
671
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
673 int id,
674 BailoutType type,
675 GetEntryMode mode) {
676 CHECK_GE(id, 0);
677 if (id >= kMaxNumberOfEntries) return NULL;
678 if (mode == ENSURE_ENTRY_CODE) {
679 EnsureCodeForDeoptimizationEntry(isolate, type, id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100680 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 CHECK_EQ(mode, CALCULATE_ENTRY_ADDRESS);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100682 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000683 DeoptimizerData* data = isolate->deoptimizer_data();
684 CHECK_LT(type, kBailoutTypesWithCodeEntry);
685 MemoryChunk* base = data->deopt_entry_code_[type];
686 return base->area_start() + (id * table_entry_size_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100687}
688
689
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690int Deoptimizer::GetDeoptimizationId(Isolate* isolate,
691 Address addr,
692 BailoutType type) {
693 DeoptimizerData* data = isolate->deoptimizer_data();
694 MemoryChunk* base = data->deopt_entry_code_[type];
695 Address start = base->area_start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400696 if (addr < start ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697 addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100698 return kNotDeoptimizationEntry;
699 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000700 DCHECK_EQ(0,
701 static_cast<int>(addr - start) % table_entry_size_);
702 return static_cast<int>(addr - start) / table_entry_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100703}
704
705
Steve Block9fac8402011-05-12 15:51:54 +0100706int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 BailoutId id,
Steve Block9fac8402011-05-12 15:51:54 +0100708 SharedFunctionInfo* shared) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100709 // TODO(kasperl): For now, we do a simple linear search for the PC
710 // offset associated with the given node id. This should probably be
711 // changed to a binary search.
712 int length = data->DeoptPoints();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100713 for (int i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000714 if (data->AstId(i) == id) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715 return data->PcAndState(i)->value();
716 }
717 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 OFStream os(stderr);
719 os << "[couldn't find pc offset for node=" << id.ToInt() << "]\n"
720 << "[method: " << shared->DebugName()->ToCString().get() << "]\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400721 << "[source:\n" << SourceCodeOf(shared) << "\n]" << std::endl;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100722
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 FATAL("unable to find pc offset during deoptimization");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100724 return -1;
725}
726
727
Steve Block44f0eee2011-05-26 01:26:41 +0100728int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100729 int length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730 // Count all entries in the deoptimizing code list of every context.
731 Object* context = isolate->heap()->native_contexts_list();
732 while (!context->IsUndefined()) {
733 Context* native_context = Context::cast(context);
734 Object* element = native_context->DeoptimizedCodeListHead();
735 while (!element->IsUndefined()) {
736 Code* code = Code::cast(element);
737 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
738 length++;
739 element = code->next_code_link();
740 }
741 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100742 }
743 return length;
744}
745
746
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100747// We rely on this function not causing a GC. It is called from generated code
748// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100749void Deoptimizer::DoComputeOutputFrames() {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100750 // Print some helpful diagnostic information.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751 if (FLAG_log_timer_events &&
752 compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
753 LOG(isolate(), CodeDeoptEvent(compiled_code_));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100754 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000755 base::ElapsedTimer timer;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100756
757 // Determine basic deoptimization information. The optimized frame is
758 // described by the input data.
759 DeoptimizationInputData* input_data =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000760 DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
761
762 if (trace_scope_ != NULL) {
763 timer.Start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400764 PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ",
765 MessageFor(bailout_type_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000766 PrintFunctionName();
767 PrintF(trace_scope_->file(),
768 " (opt #%d) @%d, FP to SP delta: %d]\n",
769 input_data->OptimizationId()->value(),
770 bailout_id_,
771 fp_to_sp_delta_);
772 if (bailout_type_ == EAGER || bailout_type_ == SOFT ||
773 (compiled_code_->is_hydrogen_stub())) {
774 compiled_code_->PrintDeoptLocation(trace_scope_->file(), bailout_id_);
775 }
776 }
777
778 BailoutId node_id = input_data->AstId(bailout_id_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100779 ByteArray* translations = input_data->TranslationByteArray();
780 unsigned translation_index =
781 input_data->TranslationIndex(bailout_id_)->value();
782
783 // Do the input frame to output frame(s) translation.
784 TranslationIterator iterator(translations, translation_index);
785 Translation::Opcode opcode =
786 static_cast<Translation::Opcode>(iterator.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000787 DCHECK(Translation::BEGIN == opcode);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100788 USE(opcode);
789 // Read the number of output frames and allocate an array for their
790 // descriptions.
791 int count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100792 iterator.Next(); // Drop JS frames count.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000793 DCHECK(output_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100794 output_ = new FrameDescription*[count];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100795 for (int i = 0; i < count; ++i) {
796 output_[i] = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100797 }
798 output_count_ = count;
799
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000800 Register fp_reg = JavaScriptFrame::fp_register();
801 stack_fp_ = reinterpret_cast<Address>(
802 input_->GetRegister(fp_reg.code()) +
803 has_alignment_padding_ * kPointerSize);
804
Ben Murdochb0fe1622011-05-05 13:52:32 +0100805 // Translate each output frame.
806 for (int i = 0; i < count; ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100807 // Read the ast node id, function, and frame height for this output frame.
808 Translation::Opcode opcode =
809 static_cast<Translation::Opcode>(iterator.Next());
810 switch (opcode) {
811 case Translation::JS_FRAME:
812 DoComputeJSFrame(&iterator, i);
813 jsframe_count_++;
814 break;
815 case Translation::ARGUMENTS_ADAPTOR_FRAME:
816 DoComputeArgumentsAdaptorFrame(&iterator, i);
817 break;
818 case Translation::CONSTRUCT_STUB_FRAME:
819 DoComputeConstructStubFrame(&iterator, i);
820 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000821 case Translation::GETTER_STUB_FRAME:
822 DoComputeAccessorStubFrame(&iterator, i, false);
823 break;
824 case Translation::SETTER_STUB_FRAME:
825 DoComputeAccessorStubFrame(&iterator, i, true);
826 break;
827 case Translation::COMPILED_STUB_FRAME:
828 DoComputeCompiledStubFrame(&iterator, i);
829 break;
830 case Translation::BEGIN:
831 case Translation::REGISTER:
832 case Translation::INT32_REGISTER:
833 case Translation::UINT32_REGISTER:
834 case Translation::DOUBLE_REGISTER:
835 case Translation::STACK_SLOT:
836 case Translation::INT32_STACK_SLOT:
837 case Translation::UINT32_STACK_SLOT:
838 case Translation::DOUBLE_STACK_SLOT:
839 case Translation::LITERAL:
840 case Translation::ARGUMENTS_OBJECT:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100841 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 FATAL("Unsupported translation");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100843 break;
844 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100845 }
846
847 // Print some helpful diagnostic information.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 if (trace_scope_ != NULL) {
849 double ms = timer.Elapsed().InMillisecondsF();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100850 int index = output_count_ - 1; // Index of the topmost frame.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400851 PrintF(trace_scope_->file(), "[deoptimizing (%s): end ",
852 MessageFor(bailout_type_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000853 PrintFunctionName();
854 PrintF(trace_scope_->file(),
855 " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
856 " took %0.3f ms]\n",
857 bailout_id_,
858 node_id.ToInt(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100859 output_[index]->GetPc(),
860 FullCodeGenerator::State2String(
861 static_cast<FullCodeGenerator::State>(
862 output_[index]->GetState()->value())),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863 has_alignment_padding_ ? "with padding" : "no padding",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100864 ms);
865 }
866}
867
868
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000869void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
870 int frame_index) {
871 BailoutId node_id = BailoutId(iterator->Next());
872 JSFunction* function;
873 if (frame_index != 0) {
874 function = JSFunction::cast(ComputeLiteral(iterator->Next()));
875 } else {
876 int closure_id = iterator->Next();
877 USE(closure_id);
878 CHECK_EQ(Translation::kSelfLiteralId, closure_id);
879 function = function_;
880 }
881 unsigned height = iterator->Next() - 1; // Do not count the context.
882 unsigned height_in_bytes = height * kPointerSize;
883 if (trace_scope_ != NULL) {
884 PrintF(trace_scope_->file(), " translating ");
885 function->PrintName(trace_scope_->file());
886 PrintF(trace_scope_->file(),
887 " => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
888 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100889
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000890 // The 'fixed' part of the frame consists of the incoming parameters and
891 // the part described by JavaScriptFrameConstants.
892 unsigned fixed_frame_size = ComputeFixedSize(function);
893 unsigned input_frame_size = input_->GetFrameSize();
894 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
895
896 // Allocate and store the output frame description.
897 FrameDescription* output_frame =
898 new(output_frame_size) FrameDescription(output_frame_size, function);
899 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
900
901 bool is_bottommost = (0 == frame_index);
902 bool is_topmost = (output_count_ - 1 == frame_index);
903 CHECK(frame_index >= 0 && frame_index < output_count_);
904 CHECK_EQ(output_[frame_index], NULL);
905 output_[frame_index] = output_frame;
906
907 // The top address for the bottommost output frame can be computed from
908 // the input frame pointer and the output frame's height. For all
909 // subsequent output frames, it can be computed from the previous one's
910 // top address and the current frame's size.
911 Register fp_reg = JavaScriptFrame::fp_register();
912 intptr_t top_address;
913 if (is_bottommost) {
914 // Determine whether the input frame contains alignment padding.
915 has_alignment_padding_ =
916 (!compiled_code_->is_turbofanned() && HasAlignmentPadding(function))
917 ? 1
918 : 0;
919 // 2 = context and function in the frame.
920 // If the optimized frame had alignment padding, adjust the frame pointer
921 // to point to the new position of the old frame pointer after padding
922 // is removed. Subtract 2 * kPointerSize for the context and function slots.
923 top_address = input_->GetRegister(fp_reg.code()) -
924 StandardFrameConstants::kFixedFrameSizeFromFp -
925 height_in_bytes + has_alignment_padding_ * kPointerSize;
926 } else {
927 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
928 }
929 output_frame->SetTop(top_address);
930
931 // Compute the incoming parameter translation.
932 int parameter_count = function->shared()->formal_parameter_count() + 1;
933 unsigned output_offset = output_frame_size;
934 unsigned input_offset = input_frame_size;
935 for (int i = 0; i < parameter_count; ++i) {
936 output_offset -= kPointerSize;
937 DoTranslateCommand(iterator, frame_index, output_offset);
938 }
939 input_offset -= (parameter_count * kPointerSize);
940
941 // There are no translation commands for the caller's pc and fp, the
942 // context, and the function. Synthesize their values and set them up
943 // explicitly.
944 //
945 // The caller's pc for the bottommost output frame is the same as in the
946 // input frame. For all subsequent output frames, it can be read from the
947 // previous one. This frame's pc can be computed from the non-optimized
948 // function code and AST id of the bailout.
949 output_offset -= kPCOnStackSize;
950 input_offset -= kPCOnStackSize;
951 intptr_t value;
952 if (is_bottommost) {
953 value = input_->GetFrameSlot(input_offset);
954 } else {
955 value = output_[frame_index - 1]->GetPc();
956 }
957 output_frame->SetCallerPc(output_offset, value);
958 if (trace_scope_ != NULL) {
959 PrintF(trace_scope_->file(),
960 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
961 V8PRIxPTR " ; caller's pc\n",
962 top_address + output_offset, output_offset, value);
963 }
964
965 // The caller's frame pointer for the bottommost output frame is the same
966 // as in the input frame. For all subsequent output frames, it can be
967 // read from the previous one. Also compute and set this frame's frame
968 // pointer.
969 output_offset -= kFPOnStackSize;
970 input_offset -= kFPOnStackSize;
971 if (is_bottommost) {
972 value = input_->GetFrameSlot(input_offset);
973 } else {
974 value = output_[frame_index - 1]->GetFp();
975 }
976 output_frame->SetCallerFp(output_offset, value);
977 intptr_t fp_value = top_address + output_offset;
978 DCHECK(!is_bottommost || (input_->GetRegister(fp_reg.code()) +
979 has_alignment_padding_ * kPointerSize) == fp_value);
980 output_frame->SetFp(fp_value);
981 if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
982 if (trace_scope_ != NULL) {
983 PrintF(trace_scope_->file(),
984 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
985 V8PRIxPTR " ; caller's fp\n",
986 fp_value, output_offset, value);
987 }
988 DCHECK(!is_bottommost || !has_alignment_padding_ ||
989 (fp_value & kPointerSize) != 0);
990
991 if (FLAG_enable_ool_constant_pool) {
992 // For the bottommost output frame the constant pool pointer can be gotten
993 // from the input frame. For subsequent output frames, it can be read from
994 // the previous frame.
995 output_offset -= kPointerSize;
996 input_offset -= kPointerSize;
997 if (is_bottommost) {
998 value = input_->GetFrameSlot(input_offset);
999 } else {
1000 value = output_[frame_index - 1]->GetConstantPool();
1001 }
1002 output_frame->SetCallerConstantPool(output_offset, value);
1003 if (trace_scope_) {
1004 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1005 V8PRIxPTR "; caller's constant_pool\n",
1006 top_address + output_offset, output_offset, value);
1007 }
1008 }
1009
1010 // For the bottommost output frame the context can be gotten from the input
1011 // frame. For all subsequent output frames it can be gotten from the function
1012 // so long as we don't inline functions that need local contexts.
1013 Register context_reg = JavaScriptFrame::context_register();
1014 output_offset -= kPointerSize;
1015 input_offset -= kPointerSize;
1016 // Read the context from the translations.
1017 DoTranslateCommand(iterator, frame_index, output_offset);
1018 value = output_frame->GetFrameSlot(output_offset);
1019 // The context should not be a placeholder for a materialized object.
1020 CHECK(value !=
1021 reinterpret_cast<intptr_t>(isolate_->heap()->arguments_marker()));
1022 if (value ==
1023 reinterpret_cast<intptr_t>(isolate_->heap()->undefined_value())) {
1024 // If the context was optimized away, just use the context from
1025 // the activation. This should only apply to Crankshaft code.
1026 CHECK(!compiled_code_->is_turbofanned());
1027 if (is_bottommost) {
1028 value = input_->GetFrameSlot(input_offset);
1029 } else {
1030 value = reinterpret_cast<intptr_t>(function->context());
1031 }
1032 output_frame->SetFrameSlot(output_offset, value);
1033 }
1034 output_frame->SetContext(value);
1035 if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
1036 if (trace_scope_ != NULL) {
1037 PrintF(trace_scope_->file(),
1038 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1039 V8PRIxPTR "; context\n",
1040 top_address + output_offset, output_offset, value);
1041 }
1042
1043 // The function was mentioned explicitly in the BEGIN_FRAME.
1044 output_offset -= kPointerSize;
1045 input_offset -= kPointerSize;
1046 value = reinterpret_cast<intptr_t>(function);
1047 // The function for the bottommost output frame should also agree with the
1048 // input frame.
1049 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
1050 output_frame->SetFrameSlot(output_offset, value);
1051 if (trace_scope_ != NULL) {
1052 PrintF(trace_scope_->file(),
1053 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1054 V8PRIxPTR "; function\n",
1055 top_address + output_offset, output_offset, value);
1056 }
1057
1058 // Translate the rest of the frame.
1059 for (unsigned i = 0; i < height; ++i) {
1060 output_offset -= kPointerSize;
1061 DoTranslateCommand(iterator, frame_index, output_offset);
1062 }
1063 CHECK_EQ(0, output_offset);
1064
1065 // Compute this frame's PC, state, and continuation.
1066 Code* non_optimized_code = function->shared()->code();
1067 FixedArray* raw_data = non_optimized_code->deoptimization_data();
1068 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
1069 Address start = non_optimized_code->instruction_start();
1070 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
1071 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
1072 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
1073 output_frame->SetPc(pc_value);
1074
1075 // Update constant pool.
1076 if (FLAG_enable_ool_constant_pool) {
1077 intptr_t constant_pool_value =
1078 reinterpret_cast<intptr_t>(non_optimized_code->constant_pool());
1079 output_frame->SetConstantPool(constant_pool_value);
1080 if (is_topmost) {
1081 Register constant_pool_reg =
1082 JavaScriptFrame::constant_pool_pointer_register();
1083 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1084 }
1085 }
1086
1087 FullCodeGenerator::State state =
1088 FullCodeGenerator::StateField::decode(pc_and_state);
1089 output_frame->SetState(Smi::FromInt(state));
1090
1091 // Set the continuation for the topmost frame.
1092 if (is_topmost && bailout_type_ != DEBUGGER) {
1093 Builtins* builtins = isolate_->builtins();
1094 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
1095 if (bailout_type_ == LAZY) {
1096 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
1097 } else if (bailout_type_ == SOFT) {
1098 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
1099 } else {
1100 CHECK_EQ(bailout_type_, EAGER);
1101 }
1102 output_frame->SetContinuation(
1103 reinterpret_cast<intptr_t>(continuation->entry()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001104 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001105}
1106
1107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001108void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
1109 int frame_index) {
1110 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
1111 unsigned height = iterator->Next();
1112 unsigned height_in_bytes = height * kPointerSize;
1113 if (trace_scope_ != NULL) {
1114 PrintF(trace_scope_->file(),
1115 " translating arguments adaptor => height=%d\n", height_in_bytes);
1116 }
1117
1118 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
1119 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1120
1121 // Allocate and store the output frame description.
1122 FrameDescription* output_frame =
1123 new(output_frame_size) FrameDescription(output_frame_size, function);
1124 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
1125
1126 // Arguments adaptor can not be topmost or bottommost.
1127 CHECK(frame_index > 0 && frame_index < output_count_ - 1);
1128 CHECK(output_[frame_index] == NULL);
1129 output_[frame_index] = output_frame;
1130
1131 // The top address of the frame is computed from the previous
1132 // frame's top and this frame's size.
1133 intptr_t top_address;
1134 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1135 output_frame->SetTop(top_address);
1136
1137 // Compute the incoming parameter translation.
1138 int parameter_count = height;
1139 unsigned output_offset = output_frame_size;
1140 for (int i = 0; i < parameter_count; ++i) {
1141 output_offset -= kPointerSize;
1142 DoTranslateCommand(iterator, frame_index, output_offset);
1143 }
1144
1145 // Read caller's PC from the previous frame.
1146 output_offset -= kPCOnStackSize;
1147 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1148 output_frame->SetCallerPc(output_offset, callers_pc);
1149 if (trace_scope_ != NULL) {
1150 PrintF(trace_scope_->file(),
1151 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1152 V8PRIxPTR " ; caller's pc\n",
1153 top_address + output_offset, output_offset, callers_pc);
1154 }
1155
1156 // Read caller's FP from the previous frame, and set this frame's FP.
1157 output_offset -= kFPOnStackSize;
1158 intptr_t value = output_[frame_index - 1]->GetFp();
1159 output_frame->SetCallerFp(output_offset, value);
1160 intptr_t fp_value = top_address + output_offset;
1161 output_frame->SetFp(fp_value);
1162 if (trace_scope_ != NULL) {
1163 PrintF(trace_scope_->file(),
1164 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1165 V8PRIxPTR " ; caller's fp\n",
1166 fp_value, output_offset, value);
1167 }
1168
1169 if (FLAG_enable_ool_constant_pool) {
1170 // Read the caller's constant pool from the previous frame.
1171 output_offset -= kPointerSize;
1172 value = output_[frame_index - 1]->GetConstantPool();
1173 output_frame->SetCallerConstantPool(output_offset, value);
1174 if (trace_scope_) {
1175 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1176 V8PRIxPTR "; caller's constant_pool\n",
1177 top_address + output_offset, output_offset, value);
1178 }
1179 }
1180
1181 // A marker value is used in place of the context.
1182 output_offset -= kPointerSize;
1183 intptr_t context = reinterpret_cast<intptr_t>(
1184 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1185 output_frame->SetFrameSlot(output_offset, context);
1186 if (trace_scope_ != NULL) {
1187 PrintF(trace_scope_->file(),
1188 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1189 V8PRIxPTR " ; context (adaptor sentinel)\n",
1190 top_address + output_offset, output_offset, context);
1191 }
1192
1193 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
1194 output_offset -= kPointerSize;
1195 value = reinterpret_cast<intptr_t>(function);
1196 output_frame->SetFrameSlot(output_offset, value);
1197 if (trace_scope_ != NULL) {
1198 PrintF(trace_scope_->file(),
1199 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1200 V8PRIxPTR " ; function\n",
1201 top_address + output_offset, output_offset, value);
1202 }
1203
1204 // Number of incoming arguments.
1205 output_offset -= kPointerSize;
1206 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1207 output_frame->SetFrameSlot(output_offset, value);
1208 if (trace_scope_ != NULL) {
1209 PrintF(trace_scope_->file(),
1210 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1211 V8PRIxPTR " ; argc (%d)\n",
1212 top_address + output_offset, output_offset, value, height - 1);
1213 }
1214
1215 DCHECK(0 == output_offset);
1216
1217 Builtins* builtins = isolate_->builtins();
1218 Code* adaptor_trampoline =
1219 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
1220 intptr_t pc_value = reinterpret_cast<intptr_t>(
1221 adaptor_trampoline->instruction_start() +
1222 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
1223 output_frame->SetPc(pc_value);
1224 if (FLAG_enable_ool_constant_pool) {
1225 intptr_t constant_pool_value =
1226 reinterpret_cast<intptr_t>(adaptor_trampoline->constant_pool());
1227 output_frame->SetConstantPool(constant_pool_value);
1228 }
1229}
1230
1231
1232void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
1233 int frame_index) {
1234 Builtins* builtins = isolate_->builtins();
1235 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
1236 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
1237 unsigned height = iterator->Next();
1238 unsigned height_in_bytes = height * kPointerSize;
1239 if (trace_scope_ != NULL) {
1240 PrintF(trace_scope_->file(),
1241 " translating construct stub => height=%d\n", height_in_bytes);
1242 }
1243
1244 unsigned fixed_frame_size = ConstructFrameConstants::kFrameSize;
1245 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1246
1247 // Allocate and store the output frame description.
1248 FrameDescription* output_frame =
1249 new(output_frame_size) FrameDescription(output_frame_size, function);
1250 output_frame->SetFrameType(StackFrame::CONSTRUCT);
1251
1252 // Construct stub can not be topmost or bottommost.
1253 DCHECK(frame_index > 0 && frame_index < output_count_ - 1);
1254 DCHECK(output_[frame_index] == NULL);
1255 output_[frame_index] = output_frame;
1256
1257 // The top address of the frame is computed from the previous
1258 // frame's top and this frame's size.
1259 intptr_t top_address;
1260 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1261 output_frame->SetTop(top_address);
1262
1263 // Compute the incoming parameter translation.
1264 int parameter_count = height;
1265 unsigned output_offset = output_frame_size;
1266 for (int i = 0; i < parameter_count; ++i) {
1267 output_offset -= kPointerSize;
1268 int deferred_object_index = deferred_objects_.length();
1269 DoTranslateCommand(iterator, frame_index, output_offset);
1270 // The allocated receiver of a construct stub frame is passed as the
1271 // receiver parameter through the translation. It might be encoding
1272 // a captured object, patch the slot address for a captured object.
1273 if (i == 0 && deferred_objects_.length() > deferred_object_index) {
1274 CHECK(!deferred_objects_[deferred_object_index].is_arguments());
1275 deferred_objects_[deferred_object_index].patch_slot_address(top_address);
1276 }
1277 }
1278
1279 // Read caller's PC from the previous frame.
1280 output_offset -= kPCOnStackSize;
1281 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1282 output_frame->SetCallerPc(output_offset, callers_pc);
1283 if (trace_scope_ != NULL) {
1284 PrintF(trace_scope_->file(),
1285 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1286 V8PRIxPTR " ; caller's pc\n",
1287 top_address + output_offset, output_offset, callers_pc);
1288 }
1289
1290 // Read caller's FP from the previous frame, and set this frame's FP.
1291 output_offset -= kFPOnStackSize;
1292 intptr_t value = output_[frame_index - 1]->GetFp();
1293 output_frame->SetCallerFp(output_offset, value);
1294 intptr_t fp_value = top_address + output_offset;
1295 output_frame->SetFp(fp_value);
1296 if (trace_scope_ != NULL) {
1297 PrintF(trace_scope_->file(),
1298 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1299 V8PRIxPTR " ; caller's fp\n",
1300 fp_value, output_offset, value);
1301 }
1302
1303 if (FLAG_enable_ool_constant_pool) {
1304 // Read the caller's constant pool from the previous frame.
1305 output_offset -= kPointerSize;
1306 value = output_[frame_index - 1]->GetConstantPool();
1307 output_frame->SetCallerConstantPool(output_offset, value);
1308 if (trace_scope_) {
1309 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1310 V8PRIxPTR " ; caller's constant pool\n",
1311 top_address + output_offset, output_offset, value);
1312 }
1313 }
1314
1315 // The context can be gotten from the previous frame.
1316 output_offset -= kPointerSize;
1317 value = output_[frame_index - 1]->GetContext();
1318 output_frame->SetFrameSlot(output_offset, value);
1319 if (trace_scope_ != NULL) {
1320 PrintF(trace_scope_->file(),
1321 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1322 V8PRIxPTR " ; context\n",
1323 top_address + output_offset, output_offset, value);
1324 }
1325
1326 // A marker value is used in place of the function.
1327 output_offset -= kPointerSize;
1328 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
1329 output_frame->SetFrameSlot(output_offset, value);
1330 if (trace_scope_ != NULL) {
1331 PrintF(trace_scope_->file(),
1332 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1333 V8PRIxPTR " ; function (construct sentinel)\n",
1334 top_address + output_offset, output_offset, value);
1335 }
1336
1337 // The output frame reflects a JSConstructStubGeneric frame.
1338 output_offset -= kPointerSize;
1339 value = reinterpret_cast<intptr_t>(construct_stub);
1340 output_frame->SetFrameSlot(output_offset, value);
1341 if (trace_scope_ != NULL) {
1342 PrintF(trace_scope_->file(),
1343 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1344 V8PRIxPTR " ; code object\n",
1345 top_address + output_offset, output_offset, value);
1346 }
1347
1348 // Number of incoming arguments.
1349 output_offset -= kPointerSize;
1350 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1351 output_frame->SetFrameSlot(output_offset, value);
1352 if (trace_scope_ != NULL) {
1353 PrintF(trace_scope_->file(),
1354 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1355 V8PRIxPTR " ; argc (%d)\n",
1356 top_address + output_offset, output_offset, value, height - 1);
1357 }
1358
1359 // Constructor function being invoked by the stub (only present on some
1360 // architectures, indicated by kConstructorOffset).
1361 if (ConstructFrameConstants::kConstructorOffset != kMinInt) {
1362 output_offset -= kPointerSize;
1363 value = reinterpret_cast<intptr_t>(function);
1364 output_frame->SetFrameSlot(output_offset, value);
1365 if (trace_scope_ != NULL) {
1366 PrintF(trace_scope_->file(),
1367 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1368 V8PRIxPTR " ; constructor function\n",
1369 top_address + output_offset, output_offset, value);
1370 }
1371 }
1372
1373 // The newly allocated object was passed as receiver in the artificial
1374 // constructor stub environment created by HEnvironment::CopyForInlining().
1375 output_offset -= kPointerSize;
1376 value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
1377 output_frame->SetFrameSlot(output_offset, value);
1378 if (trace_scope_ != NULL) {
1379 PrintF(trace_scope_->file(),
1380 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1381 V8PRIxPTR " ; allocated receiver\n",
1382 top_address + output_offset, output_offset, value);
1383 }
1384
1385 CHECK_EQ(0, output_offset);
1386
1387 intptr_t pc = reinterpret_cast<intptr_t>(
1388 construct_stub->instruction_start() +
1389 isolate_->heap()->construct_stub_deopt_pc_offset()->value());
1390 output_frame->SetPc(pc);
1391 if (FLAG_enable_ool_constant_pool) {
1392 intptr_t constant_pool_value =
1393 reinterpret_cast<intptr_t>(construct_stub->constant_pool());
1394 output_frame->SetConstantPool(constant_pool_value);
1395 }
1396}
1397
1398
1399void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
1400 int frame_index,
1401 bool is_setter_stub_frame) {
1402 JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
1403 // The receiver (and the implicit return value, if any) are expected in
1404 // registers by the LoadIC/StoreIC, so they don't belong to the output stack
1405 // frame. This means that we have to use a height of 0.
1406 unsigned height = 0;
1407 unsigned height_in_bytes = height * kPointerSize;
1408 const char* kind = is_setter_stub_frame ? "setter" : "getter";
1409 if (trace_scope_ != NULL) {
1410 PrintF(trace_scope_->file(),
1411 " translating %s stub => height=%u\n", kind, height_in_bytes);
1412 }
1413
1414 // We need 1 stack entry for the return address and enough entries for the
1415 // StackFrame::INTERNAL (FP, context, frame type, code object and constant
1416 // pool (if FLAG_enable_ool_constant_pool)- see MacroAssembler::EnterFrame).
1417 // For a setter stub frame we need one additional entry for the implicit
1418 // return value, see StoreStubCompiler::CompileStoreViaSetter.
1419 unsigned fixed_frame_entries =
1420 (StandardFrameConstants::kFixedFrameSize / kPointerSize) + 1 +
1421 (is_setter_stub_frame ? 1 : 0);
1422 unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
1423 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1424
1425 // Allocate and store the output frame description.
1426 FrameDescription* output_frame =
1427 new(output_frame_size) FrameDescription(output_frame_size, accessor);
1428 output_frame->SetFrameType(StackFrame::INTERNAL);
1429
1430 // A frame for an accessor stub can not be the topmost or bottommost one.
1431 CHECK(frame_index > 0 && frame_index < output_count_ - 1);
1432 CHECK_EQ(output_[frame_index], NULL);
1433 output_[frame_index] = output_frame;
1434
1435 // The top address of the frame is computed from the previous frame's top and
1436 // this frame's size.
1437 intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1438 output_frame->SetTop(top_address);
1439
1440 unsigned output_offset = output_frame_size;
1441
1442 // Read caller's PC from the previous frame.
1443 output_offset -= kPCOnStackSize;
1444 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1445 output_frame->SetCallerPc(output_offset, callers_pc);
1446 if (trace_scope_ != NULL) {
1447 PrintF(trace_scope_->file(),
1448 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1449 " ; caller's pc\n",
1450 top_address + output_offset, output_offset, callers_pc);
1451 }
1452
1453 // Read caller's FP from the previous frame, and set this frame's FP.
1454 output_offset -= kFPOnStackSize;
1455 intptr_t value = output_[frame_index - 1]->GetFp();
1456 output_frame->SetCallerFp(output_offset, value);
1457 intptr_t fp_value = top_address + output_offset;
1458 output_frame->SetFp(fp_value);
1459 if (trace_scope_ != NULL) {
1460 PrintF(trace_scope_->file(),
1461 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1462 " ; caller's fp\n",
1463 fp_value, output_offset, value);
1464 }
1465
1466 if (FLAG_enable_ool_constant_pool) {
1467 // Read the caller's constant pool from the previous frame.
1468 output_offset -= kPointerSize;
1469 value = output_[frame_index - 1]->GetConstantPool();
1470 output_frame->SetCallerConstantPool(output_offset, value);
1471 if (trace_scope_) {
1472 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1473 V8PRIxPTR " ; caller's constant pool\n",
1474 top_address + output_offset, output_offset, value);
1475 }
1476 }
1477
1478 // The context can be gotten from the previous frame.
1479 output_offset -= kPointerSize;
1480 value = output_[frame_index - 1]->GetContext();
1481 output_frame->SetFrameSlot(output_offset, value);
1482 if (trace_scope_ != NULL) {
1483 PrintF(trace_scope_->file(),
1484 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1485 " ; context\n",
1486 top_address + output_offset, output_offset, value);
1487 }
1488
1489 // A marker value is used in place of the function.
1490 output_offset -= kPointerSize;
1491 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
1492 output_frame->SetFrameSlot(output_offset, value);
1493 if (trace_scope_ != NULL) {
1494 PrintF(trace_scope_->file(),
1495 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1496 " ; function (%s sentinel)\n",
1497 top_address + output_offset, output_offset, value, kind);
1498 }
1499
1500 // Get Code object from accessor stub.
1501 output_offset -= kPointerSize;
1502 Builtins::Name name = is_setter_stub_frame ?
1503 Builtins::kStoreIC_Setter_ForDeopt :
1504 Builtins::kLoadIC_Getter_ForDeopt;
1505 Code* accessor_stub = isolate_->builtins()->builtin(name);
1506 value = reinterpret_cast<intptr_t>(accessor_stub);
1507 output_frame->SetFrameSlot(output_offset, value);
1508 if (trace_scope_ != NULL) {
1509 PrintF(trace_scope_->file(),
1510 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1511 " ; code object\n",
1512 top_address + output_offset, output_offset, value);
1513 }
1514
1515 // Skip receiver.
1516 DoTranslateObjectAndSkip(iterator);
1517
1518 if (is_setter_stub_frame) {
1519 // The implicit return value was part of the artificial setter stub
1520 // environment.
1521 output_offset -= kPointerSize;
1522 DoTranslateCommand(iterator, frame_index, output_offset);
1523 }
1524
1525 CHECK_EQ(output_offset, 0);
1526
1527 Smi* offset = is_setter_stub_frame ?
1528 isolate_->heap()->setter_stub_deopt_pc_offset() :
1529 isolate_->heap()->getter_stub_deopt_pc_offset();
1530 intptr_t pc = reinterpret_cast<intptr_t>(
1531 accessor_stub->instruction_start() + offset->value());
1532 output_frame->SetPc(pc);
1533 if (FLAG_enable_ool_constant_pool) {
1534 intptr_t constant_pool_value =
1535 reinterpret_cast<intptr_t>(accessor_stub->constant_pool());
1536 output_frame->SetConstantPool(constant_pool_value);
1537 }
1538}
1539
1540
1541void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
1542 int frame_index) {
1543 //
1544 // FROM TO
1545 // | .... | | .... |
1546 // +-------------------------+ +-------------------------+
1547 // | JSFunction continuation | | JSFunction continuation |
1548 // +-------------------------+ +-------------------------+
1549 // | | saved frame (FP) | | saved frame (FP) |
1550 // | +=========================+<-fpreg +=========================+<-fpreg
1551 // | |constant pool (if ool_cp)| |constant pool (if ool_cp)|
1552 // | +-------------------------+ +-------------------------|
1553 // | | JSFunction context | | JSFunction context |
1554 // v +-------------------------+ +-------------------------|
1555 // | COMPILED_STUB marker | | STUB_FAILURE marker |
1556 // +-------------------------+ +-------------------------+
1557 // | | | caller args.arguments_ |
1558 // | ... | +-------------------------+
1559 // | | | caller args.length_ |
1560 // |-------------------------|<-spreg +-------------------------+
1561 // | caller args pointer |
1562 // +-------------------------+
1563 // | caller stack param 1 |
1564 // parameters in registers +-------------------------+
1565 // and spilled to stack | .... |
1566 // +-------------------------+
1567 // | caller stack param n |
1568 // +-------------------------+<-spreg
1569 // reg = number of parameters
1570 // reg = failure handler address
1571 // reg = saved frame
1572 // reg = JSFunction context
1573 //
1574
1575 CHECK(compiled_code_->is_hydrogen_stub());
1576 int major_key = CodeStub::GetMajorKey(compiled_code_);
1577 CodeStubDescriptor descriptor(isolate_, compiled_code_->stub_key());
1578
1579 // The output frame must have room for all pushed register parameters
1580 // and the standard stack frame slots. Include space for an argument
1581 // object to the callee and optionally the space to pass the argument
1582 // object to the stub failure handler.
1583 int param_count = descriptor.GetEnvironmentParameterCount();
1584 CHECK_GE(param_count, 0);
1585
1586 int height_in_bytes = kPointerSize * param_count + sizeof(Arguments) +
1587 kPointerSize;
1588 int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
1589 int input_frame_size = input_->GetFrameSize();
1590 int output_frame_size = height_in_bytes + fixed_frame_size;
1591 if (trace_scope_ != NULL) {
1592 PrintF(trace_scope_->file(),
1593 " translating %s => StubFailureTrampolineStub, height=%d\n",
1594 CodeStub::MajorName(static_cast<CodeStub::Major>(major_key), false),
1595 height_in_bytes);
1596 }
1597
1598 // The stub failure trampoline is a single frame.
1599 FrameDescription* output_frame =
1600 new(output_frame_size) FrameDescription(output_frame_size, NULL);
1601 output_frame->SetFrameType(StackFrame::STUB_FAILURE_TRAMPOLINE);
1602 CHECK_EQ(frame_index, 0);
1603 output_[frame_index] = output_frame;
1604
1605 // The top address for the output frame can be computed from the input
1606 // frame pointer and the output frame's height. Subtract space for the
1607 // context and function slots.
1608 Register fp_reg = StubFailureTrampolineFrame::fp_register();
1609 intptr_t top_address = input_->GetRegister(fp_reg.code()) -
1610 StandardFrameConstants::kFixedFrameSizeFromFp - height_in_bytes;
1611 output_frame->SetTop(top_address);
1612
1613 // Read caller's PC (JSFunction continuation) from the input frame.
1614 unsigned input_frame_offset = input_frame_size - kPCOnStackSize;
1615 unsigned output_frame_offset = output_frame_size - kFPOnStackSize;
1616 intptr_t value = input_->GetFrameSlot(input_frame_offset);
1617 output_frame->SetCallerPc(output_frame_offset, value);
1618 if (trace_scope_ != NULL) {
1619 PrintF(trace_scope_->file(),
1620 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1621 V8PRIxPTR " ; caller's pc\n",
1622 top_address + output_frame_offset, output_frame_offset, value);
1623 }
1624
1625 // Read caller's FP from the input frame, and set this frame's FP.
1626 input_frame_offset -= kFPOnStackSize;
1627 value = input_->GetFrameSlot(input_frame_offset);
1628 output_frame_offset -= kFPOnStackSize;
1629 output_frame->SetCallerFp(output_frame_offset, value);
1630 intptr_t frame_ptr = input_->GetRegister(fp_reg.code());
1631 output_frame->SetRegister(fp_reg.code(), frame_ptr);
1632 output_frame->SetFp(frame_ptr);
1633 if (trace_scope_ != NULL) {
1634 PrintF(trace_scope_->file(),
1635 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1636 V8PRIxPTR " ; caller's fp\n",
1637 top_address + output_frame_offset, output_frame_offset, value);
1638 }
1639
1640 if (FLAG_enable_ool_constant_pool) {
1641 // Read the caller's constant pool from the input frame.
1642 input_frame_offset -= kPointerSize;
1643 value = input_->GetFrameSlot(input_frame_offset);
1644 output_frame_offset -= kPointerSize;
1645 output_frame->SetCallerConstantPool(output_frame_offset, value);
1646 if (trace_scope_) {
1647 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1648 V8PRIxPTR " ; caller's constant_pool\n",
1649 top_address + output_frame_offset, output_frame_offset, value);
1650 }
1651 }
1652
1653 // The context can be gotten from the input frame.
1654 Register context_reg = StubFailureTrampolineFrame::context_register();
1655 input_frame_offset -= kPointerSize;
1656 value = input_->GetFrameSlot(input_frame_offset);
1657 output_frame->SetRegister(context_reg.code(), value);
1658 output_frame_offset -= kPointerSize;
1659 output_frame->SetFrameSlot(output_frame_offset, value);
1660 CHECK(reinterpret_cast<Object*>(value)->IsContext());
1661 if (trace_scope_ != NULL) {
1662 PrintF(trace_scope_->file(),
1663 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1664 V8PRIxPTR " ; context\n",
1665 top_address + output_frame_offset, output_frame_offset, value);
1666 }
1667
1668 // A marker value is used in place of the function.
1669 output_frame_offset -= kPointerSize;
1670 value = reinterpret_cast<intptr_t>(
1671 Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
1672 output_frame->SetFrameSlot(output_frame_offset, value);
1673 if (trace_scope_ != NULL) {
1674 PrintF(trace_scope_->file(),
1675 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1676 V8PRIxPTR " ; function (stub failure sentinel)\n",
1677 top_address + output_frame_offset, output_frame_offset, value);
1678 }
1679
1680 intptr_t caller_arg_count = 0;
1681 bool arg_count_known = !descriptor.stack_parameter_count().is_valid();
1682
1683 // Build the Arguments object for the caller's parameters and a pointer to it.
1684 output_frame_offset -= kPointerSize;
1685 int args_arguments_offset = output_frame_offset;
1686 intptr_t the_hole = reinterpret_cast<intptr_t>(
1687 isolate_->heap()->the_hole_value());
1688 if (arg_count_known) {
1689 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1690 (caller_arg_count - 1) * kPointerSize;
1691 } else {
1692 value = the_hole;
1693 }
1694
1695 output_frame->SetFrameSlot(args_arguments_offset, value);
1696 if (trace_scope_ != NULL) {
1697 PrintF(trace_scope_->file(),
1698 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1699 V8PRIxPTR " ; args.arguments %s\n",
1700 top_address + args_arguments_offset, args_arguments_offset, value,
1701 arg_count_known ? "" : "(the hole)");
1702 }
1703
1704 output_frame_offset -= kPointerSize;
1705 int length_frame_offset = output_frame_offset;
1706 value = arg_count_known ? caller_arg_count : the_hole;
1707 output_frame->SetFrameSlot(length_frame_offset, value);
1708 if (trace_scope_ != NULL) {
1709 PrintF(trace_scope_->file(),
1710 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1711 V8PRIxPTR " ; args.length %s\n",
1712 top_address + length_frame_offset, length_frame_offset, value,
1713 arg_count_known ? "" : "(the hole)");
1714 }
1715
1716 output_frame_offset -= kPointerSize;
1717 value = frame_ptr + StandardFrameConstants::kCallerSPOffset -
1718 (output_frame_size - output_frame_offset) + kPointerSize;
1719 output_frame->SetFrameSlot(output_frame_offset, value);
1720 if (trace_scope_ != NULL) {
1721 PrintF(trace_scope_->file(),
1722 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1723 V8PRIxPTR " ; args*\n",
1724 top_address + output_frame_offset, output_frame_offset, value);
1725 }
1726
1727 // Copy the register parameters to the failure frame.
1728 int arguments_length_offset = -1;
1729 for (int i = 0; i < param_count; ++i) {
1730 output_frame_offset -= kPointerSize;
1731 DoTranslateCommand(iterator, 0, output_frame_offset);
1732
1733 if (!arg_count_known && descriptor.IsEnvironmentParameterCountRegister(i)) {
1734 arguments_length_offset = output_frame_offset;
1735 }
1736 }
1737
1738 CHECK_EQ(output_frame_offset, 0);
1739
1740 if (!arg_count_known) {
1741 CHECK_GE(arguments_length_offset, 0);
1742 // We know it's a smi because 1) the code stub guarantees the stack
1743 // parameter count is in smi range, and 2) the DoTranslateCommand in the
1744 // parameter loop above translated that to a tagged value.
1745 Smi* smi_caller_arg_count = reinterpret_cast<Smi*>(
1746 output_frame->GetFrameSlot(arguments_length_offset));
1747 caller_arg_count = smi_caller_arg_count->value();
1748 output_frame->SetFrameSlot(length_frame_offset, caller_arg_count);
1749 if (trace_scope_ != NULL) {
1750 PrintF(trace_scope_->file(),
1751 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1752 V8PRIxPTR " ; args.length\n",
1753 top_address + length_frame_offset, length_frame_offset,
1754 caller_arg_count);
1755 }
1756 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1757 (caller_arg_count - 1) * kPointerSize;
1758 output_frame->SetFrameSlot(args_arguments_offset, value);
1759 if (trace_scope_ != NULL) {
1760 PrintF(trace_scope_->file(),
1761 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1762 V8PRIxPTR " ; args.arguments\n",
1763 top_address + args_arguments_offset, args_arguments_offset,
1764 value);
1765 }
1766 }
1767
1768 // Copy the double registers from the input into the output frame.
1769 CopyDoubleRegisters(output_frame);
1770
1771 // Fill registers containing handler and number of parameters.
1772 SetPlatformCompiledStubRegisters(output_frame, &descriptor);
1773
1774 // Compute this frame's PC, state, and continuation.
1775 Code* trampoline = NULL;
1776 StubFunctionMode function_mode = descriptor.function_mode();
1777 StubFailureTrampolineStub(isolate_,
1778 function_mode).FindCodeInCache(&trampoline);
1779 DCHECK(trampoline != NULL);
1780 output_frame->SetPc(reinterpret_cast<intptr_t>(
1781 trampoline->instruction_start()));
1782 if (FLAG_enable_ool_constant_pool) {
1783 Register constant_pool_reg =
1784 StubFailureTrampolineFrame::constant_pool_pointer_register();
1785 intptr_t constant_pool_value =
1786 reinterpret_cast<intptr_t>(trampoline->constant_pool());
1787 output_frame->SetConstantPool(constant_pool_value);
1788 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1789 }
1790 output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
1791 Code* notify_failure =
1792 isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles);
1793 output_frame->SetContinuation(
1794 reinterpret_cast<intptr_t>(notify_failure->entry()));
1795}
1796
1797
1798Handle<Object> Deoptimizer::MaterializeNextHeapObject() {
1799 int object_index = materialization_object_index_++;
1800 ObjectMaterializationDescriptor desc = deferred_objects_[object_index];
1801 const int length = desc.object_length();
1802
1803 if (desc.duplicate_object() >= 0) {
1804 // Found a previously materialized object by de-duplication.
1805 object_index = desc.duplicate_object();
1806 materialized_objects_->Add(Handle<Object>());
1807 } else if (desc.is_arguments() && ArgumentsObjectIsAdapted(object_index)) {
1808 // Use the arguments adapter frame we just built to materialize the
1809 // arguments object. FunctionGetArguments can't throw an exception.
1810 Handle<JSFunction> function = ArgumentsObjectFunction(object_index);
1811 Handle<JSObject> arguments = Handle<JSObject>::cast(
1812 Accessors::FunctionGetArguments(function));
1813 materialized_objects_->Add(arguments);
1814 // To keep consistent object counters, we still materialize the
1815 // nested values (but we throw them away).
1816 for (int i = 0; i < length; ++i) {
1817 MaterializeNextValue();
1818 }
1819 } else if (desc.is_arguments()) {
1820 // Construct an arguments object and copy the parameters to a newly
1821 // allocated arguments object backing store.
1822 Handle<JSFunction> function = ArgumentsObjectFunction(object_index);
1823 Handle<JSObject> arguments =
1824 isolate_->factory()->NewArgumentsObject(function, length);
1825 Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
1826 DCHECK_EQ(array->length(), length);
1827 arguments->set_elements(*array);
1828 materialized_objects_->Add(arguments);
1829 for (int i = 0; i < length; ++i) {
1830 Handle<Object> value = MaterializeNextValue();
1831 array->set(i, *value);
1832 }
1833 } else {
1834 // Dispatch on the instance type of the object to be materialized.
1835 // We also need to make sure that the representation of all fields
1836 // in the given object are general enough to hold a tagged value.
1837 Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
1838 Handle<Map>::cast(MaterializeNextValue()));
1839 switch (map->instance_type()) {
1840 case MUTABLE_HEAP_NUMBER_TYPE:
1841 case HEAP_NUMBER_TYPE: {
1842 // Reuse the HeapNumber value directly as it is already properly
1843 // tagged and skip materializing the HeapNumber explicitly. Turn mutable
1844 // heap numbers immutable.
1845 Handle<Object> object = MaterializeNextValue();
1846 if (object_index < prev_materialized_count_) {
1847 materialized_objects_->Add(Handle<Object>(
1848 previously_materialized_objects_->get(object_index), isolate_));
1849 } else {
1850 materialized_objects_->Add(object);
1851 }
1852 materialization_value_index_ += kDoubleSize / kPointerSize - 1;
1853 break;
1854 }
1855 case JS_OBJECT_TYPE: {
1856 Handle<JSObject> object =
1857 isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED, false);
1858 if (object_index < prev_materialized_count_) {
1859 materialized_objects_->Add(Handle<Object>(
1860 previously_materialized_objects_->get(object_index), isolate_));
1861 } else {
1862 materialized_objects_->Add(object);
1863 }
1864 Handle<Object> properties = MaterializeNextValue();
1865 Handle<Object> elements = MaterializeNextValue();
1866 object->set_properties(FixedArray::cast(*properties));
1867 object->set_elements(FixedArrayBase::cast(*elements));
1868 for (int i = 0; i < length - 3; ++i) {
1869 Handle<Object> value = MaterializeNextValue();
1870 FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
1871 object->FastPropertyAtPut(index, *value);
1872 }
1873 break;
1874 }
1875 case JS_ARRAY_TYPE: {
1876 Handle<JSArray> object =
1877 isolate_->factory()->NewJSArray(0, map->elements_kind());
1878 if (object_index < prev_materialized_count_) {
1879 materialized_objects_->Add(Handle<Object>(
1880 previously_materialized_objects_->get(object_index), isolate_));
1881 } else {
1882 materialized_objects_->Add(object);
1883 }
1884 Handle<Object> properties = MaterializeNextValue();
1885 Handle<Object> elements = MaterializeNextValue();
1886 Handle<Object> length = MaterializeNextValue();
1887 object->set_properties(FixedArray::cast(*properties));
1888 object->set_elements(FixedArrayBase::cast(*elements));
1889 object->set_length(*length);
1890 break;
1891 }
1892 default:
1893 PrintF(stderr,
1894 "[couldn't handle instance type %d]\n", map->instance_type());
1895 FATAL("Unsupported instance type");
1896 }
1897 }
1898
1899 return materialized_objects_->at(object_index);
1900}
1901
1902
1903Handle<Object> Deoptimizer::MaterializeNextValue() {
1904 int value_index = materialization_value_index_++;
1905 Handle<Object> value = materialized_values_->at(value_index);
1906 if (value->IsMutableHeapNumber()) {
1907 HeapNumber::cast(*value)->set_map(isolate_->heap()->heap_number_map());
1908 }
1909 if (*value == isolate_->heap()->arguments_marker()) {
1910 value = MaterializeNextHeapObject();
1911 }
1912 return value;
1913}
1914
1915
1916void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
1917 DCHECK_NE(DEBUGGER, bailout_type_);
1918
1919 MaterializedObjectStore* materialized_store =
1920 isolate_->materialized_object_store();
1921 previously_materialized_objects_ = materialized_store->Get(stack_fp_);
1922 prev_materialized_count_ = previously_materialized_objects_.is_null() ?
1923 0 : previously_materialized_objects_->length();
1924
1925 // Walk all JavaScript output frames with the given frame iterator.
1926 for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
1927 if (frame_index != 0) it->Advance();
1928 JavaScriptFrame* frame = it->frame();
1929 jsframe_functions_.Add(handle(frame->function(), isolate_));
1930 jsframe_has_adapted_arguments_.Add(frame->has_adapted_arguments());
1931 }
1932
1933 // Handlify all tagged object values before triggering any allocation.
1934 List<Handle<Object> > values(deferred_objects_tagged_values_.length());
1935 for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) {
1936 values.Add(Handle<Object>(deferred_objects_tagged_values_[i], isolate_));
1937 }
1938
1939 // Play it safe and clear all unhandlified values before we continue.
1940 deferred_objects_tagged_values_.Clear();
1941
1942 // Materialize all heap numbers before looking at arguments because when the
1943 // output frames are used to materialize arguments objects later on they need
1944 // to already contain valid heap numbers.
1945 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
1946 HeapNumberMaterializationDescriptor<Address> d = deferred_heap_numbers_[i];
1947 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
1948 if (trace_scope_ != NULL) {
1949 PrintF(trace_scope_->file(),
1950 "Materialized a new heap number %p [%e] in slot %p\n",
1951 reinterpret_cast<void*>(*num),
1952 d.value(),
1953 d.destination());
1954 }
1955 Memory::Object_at(d.destination()) = *num;
1956 }
1957
1958 // Materialize all heap numbers required for arguments/captured objects.
1959 for (int i = 0; i < deferred_objects_double_values_.length(); i++) {
1960 HeapNumberMaterializationDescriptor<int> d =
1961 deferred_objects_double_values_[i];
1962 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
1963 if (trace_scope_ != NULL) {
1964 PrintF(trace_scope_->file(),
1965 "Materialized a new heap number %p [%e] for object at %d\n",
1966 reinterpret_cast<void*>(*num),
1967 d.value(),
1968 d.destination());
1969 }
1970 DCHECK(values.at(d.destination())->IsTheHole());
1971 values.Set(d.destination(), num);
1972 }
1973
1974 // Play it safe and clear all object double values before we continue.
1975 deferred_objects_double_values_.Clear();
1976
1977 // Materialize arguments/captured objects.
1978 if (!deferred_objects_.is_empty()) {
1979 List<Handle<Object> > materialized_objects(deferred_objects_.length());
1980 materialized_objects_ = &materialized_objects;
1981 materialized_values_ = &values;
1982
1983 while (materialization_object_index_ < deferred_objects_.length()) {
1984 int object_index = materialization_object_index_;
1985 ObjectMaterializationDescriptor descriptor =
1986 deferred_objects_.at(object_index);
1987
1988 // Find a previously materialized object by de-duplication or
1989 // materialize a new instance of the object if necessary. Store
1990 // the materialized object into the frame slot.
1991 Handle<Object> object = MaterializeNextHeapObject();
1992 if (descriptor.slot_address() != NULL) {
1993 Memory::Object_at(descriptor.slot_address()) = *object;
1994 }
1995 if (trace_scope_ != NULL) {
1996 if (descriptor.is_arguments()) {
1997 PrintF(trace_scope_->file(),
1998 "Materialized %sarguments object of length %d for %p: ",
1999 ArgumentsObjectIsAdapted(object_index) ? "(adapted) " : "",
2000 Handle<JSObject>::cast(object)->elements()->length(),
2001 reinterpret_cast<void*>(descriptor.slot_address()));
2002 } else {
2003 PrintF(trace_scope_->file(),
2004 "Materialized captured object of size %d for %p: ",
2005 Handle<HeapObject>::cast(object)->Size(),
2006 reinterpret_cast<void*>(descriptor.slot_address()));
2007 }
2008 object->ShortPrint(trace_scope_->file());
2009 PrintF(trace_scope_->file(), "\n");
2010 }
2011 }
2012
2013 CHECK_EQ(materialization_object_index_, materialized_objects_->length());
2014 CHECK_EQ(materialization_value_index_, materialized_values_->length());
2015 }
2016
2017 if (prev_materialized_count_ > 0) {
2018 materialized_store->Remove(stack_fp_);
2019 }
2020}
2021
2022
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002023void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002024 Address parameters_top,
2025 uint32_t parameters_size,
2026 Address expressions_top,
2027 uint32_t expressions_size,
2028 DeoptimizedFrameInfo* info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002029 CHECK_EQ(DEBUGGER, bailout_type_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002030 Address parameters_bottom = parameters_top + parameters_size;
2031 Address expressions_bottom = expressions_top + expressions_size;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002032 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002033 HeapNumberMaterializationDescriptor<Address> d = deferred_heap_numbers_[i];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002034
2035 // Check of the heap number to materialize actually belong to the frame
2036 // being extracted.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002037 Address slot = d.destination();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002038 if (parameters_top <= slot && slot < parameters_bottom) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002039 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002040
2041 int index = (info->parameters_count() - 1) -
2042 static_cast<int>(slot - parameters_top) / kPointerSize;
2043
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002044 if (trace_scope_ != NULL) {
2045 PrintF(trace_scope_->file(),
2046 "Materializing a new heap number %p [%e] in slot %p"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002047 "for parameter slot #%d\n",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002048 reinterpret_cast<void*>(*num),
2049 d.value(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002050 d.destination(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002051 index);
2052 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002053
2054 info->SetParameter(index, *num);
2055 } else if (expressions_top <= slot && slot < expressions_bottom) {
2056 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
2057
2058 int index = info->expression_count() - 1 -
2059 static_cast<int>(slot - expressions_top) / kPointerSize;
2060
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002061 if (trace_scope_ != NULL) {
2062 PrintF(trace_scope_->file(),
2063 "Materializing a new heap number %p [%e] in slot %p"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002064 "for expression slot #%d\n",
2065 reinterpret_cast<void*>(*num),
2066 d.value(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002067 d.destination(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002068 index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002069 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002070
2071 info->SetExpression(index, *num);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002072 }
2073 }
2074}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002075
2076
2077static const char* TraceValueType(bool is_smi) {
2078 if (is_smi) {
2079 return "smi";
2080 }
2081
2082 return "heap number";
2083}
2084
2085
2086void Deoptimizer::DoTranslateObjectAndSkip(TranslationIterator* iterator) {
2087 Translation::Opcode opcode =
2088 static_cast<Translation::Opcode>(iterator->Next());
2089
2090 switch (opcode) {
2091 case Translation::BEGIN:
2092 case Translation::JS_FRAME:
2093 case Translation::ARGUMENTS_ADAPTOR_FRAME:
2094 case Translation::CONSTRUCT_STUB_FRAME:
2095 case Translation::GETTER_STUB_FRAME:
2096 case Translation::SETTER_STUB_FRAME:
2097 case Translation::COMPILED_STUB_FRAME: {
2098 FATAL("Unexpected frame start translation opcode");
2099 return;
2100 }
2101
2102 case Translation::REGISTER:
2103 case Translation::INT32_REGISTER:
2104 case Translation::UINT32_REGISTER:
2105 case Translation::DOUBLE_REGISTER:
2106 case Translation::STACK_SLOT:
2107 case Translation::INT32_STACK_SLOT:
2108 case Translation::UINT32_STACK_SLOT:
2109 case Translation::DOUBLE_STACK_SLOT:
2110 case Translation::LITERAL: {
2111 // The value is not part of any materialized object, so we can ignore it.
2112 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
2113 return;
2114 }
2115
2116 case Translation::DUPLICATED_OBJECT: {
2117 int object_index = iterator->Next();
2118 if (trace_scope_ != NULL) {
2119 PrintF(trace_scope_->file(), " skipping object ");
2120 PrintF(trace_scope_->file(),
2121 " ; duplicate of object #%d\n", object_index);
2122 }
2123 AddObjectDuplication(0, object_index);
2124 return;
2125 }
2126
2127 case Translation::ARGUMENTS_OBJECT:
2128 case Translation::CAPTURED_OBJECT: {
2129 int length = iterator->Next();
2130 bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
2131 if (trace_scope_ != NULL) {
2132 PrintF(trace_scope_->file(), " skipping object ");
2133 PrintF(trace_scope_->file(),
2134 " ; object (length = %d, is_args = %d)\n", length, is_args);
2135 }
2136
2137 AddObjectStart(0, length, is_args);
2138
2139 // We save the object values on the side and materialize the actual
2140 // object after the deoptimized frame is built.
2141 int object_index = deferred_objects_.length() - 1;
2142 for (int i = 0; i < length; i++) {
2143 DoTranslateObject(iterator, object_index, i);
2144 }
2145 return;
2146 }
2147 }
2148
2149 FATAL("Unexpected translation opcode");
2150}
2151
2152
2153void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
2154 int object_index,
2155 int field_index) {
2156 disasm::NameConverter converter;
2157 Address object_slot = deferred_objects_[object_index].slot_address();
2158
2159 Translation::Opcode opcode =
2160 static_cast<Translation::Opcode>(iterator->Next());
2161
2162 switch (opcode) {
2163 case Translation::BEGIN:
2164 case Translation::JS_FRAME:
2165 case Translation::ARGUMENTS_ADAPTOR_FRAME:
2166 case Translation::CONSTRUCT_STUB_FRAME:
2167 case Translation::GETTER_STUB_FRAME:
2168 case Translation::SETTER_STUB_FRAME:
2169 case Translation::COMPILED_STUB_FRAME:
2170 FATAL("Unexpected frame start translation opcode");
2171 return;
2172
2173 case Translation::REGISTER: {
2174 int input_reg = iterator->Next();
2175 intptr_t input_value = input_->GetRegister(input_reg);
2176 if (trace_scope_ != NULL) {
2177 PrintF(trace_scope_->file(),
2178 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2179 reinterpret_cast<intptr_t>(object_slot),
2180 field_index);
2181 PrintF(trace_scope_->file(),
2182 "0x%08" V8PRIxPTR " ; %s ", input_value,
2183 converter.NameOfCPURegister(input_reg));
2184 reinterpret_cast<Object*>(input_value)->ShortPrint(
2185 trace_scope_->file());
2186 PrintF(trace_scope_->file(),
2187 "\n");
2188 }
2189 AddObjectTaggedValue(input_value);
2190 return;
2191 }
2192
2193 case Translation::INT32_REGISTER: {
2194 int input_reg = iterator->Next();
2195 intptr_t value = input_->GetRegister(input_reg);
2196 bool is_smi = Smi::IsValid(value);
2197 if (trace_scope_ != NULL) {
2198 PrintF(trace_scope_->file(),
2199 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2200 reinterpret_cast<intptr_t>(object_slot),
2201 field_index);
2202 PrintF(trace_scope_->file(),
2203 "%" V8PRIdPTR " ; %s (%s)\n", value,
2204 converter.NameOfCPURegister(input_reg),
2205 TraceValueType(is_smi));
2206 }
2207 if (is_smi) {
2208 intptr_t tagged_value =
2209 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2210 AddObjectTaggedValue(tagged_value);
2211 } else {
2212 double double_value = static_cast<double>(static_cast<int32_t>(value));
2213 AddObjectDoubleValue(double_value);
2214 }
2215 return;
2216 }
2217
2218 case Translation::UINT32_REGISTER: {
2219 int input_reg = iterator->Next();
2220 uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
2221 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
2222 if (trace_scope_ != NULL) {
2223 PrintF(trace_scope_->file(),
2224 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2225 reinterpret_cast<intptr_t>(object_slot),
2226 field_index);
2227 PrintF(trace_scope_->file(),
2228 "%" V8PRIdPTR " ; uint %s (%s)\n", value,
2229 converter.NameOfCPURegister(input_reg),
2230 TraceValueType(is_smi));
2231 }
2232 if (is_smi) {
2233 intptr_t tagged_value =
2234 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2235 AddObjectTaggedValue(tagged_value);
2236 } else {
2237 double double_value = static_cast<double>(static_cast<uint32_t>(value));
2238 AddObjectDoubleValue(double_value);
2239 }
2240 return;
2241 }
2242
2243 case Translation::DOUBLE_REGISTER: {
2244 int input_reg = iterator->Next();
2245 double value = input_->GetDoubleRegister(input_reg);
2246 if (trace_scope_ != NULL) {
2247 PrintF(trace_scope_->file(),
2248 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2249 reinterpret_cast<intptr_t>(object_slot),
2250 field_index);
2251 PrintF(trace_scope_->file(),
2252 "%e ; %s\n", value,
2253 DoubleRegister::AllocationIndexToString(input_reg));
2254 }
2255 AddObjectDoubleValue(value);
2256 return;
2257 }
2258
2259 case Translation::STACK_SLOT: {
2260 int input_slot_index = iterator->Next();
2261 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2262 intptr_t input_value = input_->GetFrameSlot(input_offset);
2263 if (trace_scope_ != NULL) {
2264 PrintF(trace_scope_->file(),
2265 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2266 reinterpret_cast<intptr_t>(object_slot),
2267 field_index);
2268 PrintF(trace_scope_->file(),
2269 "0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
2270 reinterpret_cast<Object*>(input_value)->ShortPrint(
2271 trace_scope_->file());
2272 PrintF(trace_scope_->file(),
2273 "\n");
2274 }
2275 AddObjectTaggedValue(input_value);
2276 return;
2277 }
2278
2279 case Translation::INT32_STACK_SLOT: {
2280 int input_slot_index = iterator->Next();
2281 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2282 intptr_t value = input_->GetFrameSlot(input_offset);
2283 bool is_smi = Smi::IsValid(value);
2284 if (trace_scope_ != NULL) {
2285 PrintF(trace_scope_->file(),
2286 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2287 reinterpret_cast<intptr_t>(object_slot),
2288 field_index);
2289 PrintF(trace_scope_->file(),
2290 "%" V8PRIdPTR " ; [sp + %d] (%s)\n",
2291 value, input_offset, TraceValueType(is_smi));
2292 }
2293 if (is_smi) {
2294 intptr_t tagged_value =
2295 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2296 AddObjectTaggedValue(tagged_value);
2297 } else {
2298 double double_value = static_cast<double>(static_cast<int32_t>(value));
2299 AddObjectDoubleValue(double_value);
2300 }
2301 return;
2302 }
2303
2304 case Translation::UINT32_STACK_SLOT: {
2305 int input_slot_index = iterator->Next();
2306 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2307 uintptr_t value =
2308 static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
2309 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
2310 if (trace_scope_ != NULL) {
2311 PrintF(trace_scope_->file(),
2312 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2313 reinterpret_cast<intptr_t>(object_slot),
2314 field_index);
2315 PrintF(trace_scope_->file(),
2316 "%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
2317 value, input_offset, TraceValueType(is_smi));
2318 }
2319 if (is_smi) {
2320 intptr_t tagged_value =
2321 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2322 AddObjectTaggedValue(tagged_value);
2323 } else {
2324 double double_value = static_cast<double>(static_cast<uint32_t>(value));
2325 AddObjectDoubleValue(double_value);
2326 }
2327 return;
2328 }
2329
2330 case Translation::DOUBLE_STACK_SLOT: {
2331 int input_slot_index = iterator->Next();
2332 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2333 double value = input_->GetDoubleFrameSlot(input_offset);
2334 if (trace_scope_ != NULL) {
2335 PrintF(trace_scope_->file(),
2336 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2337 reinterpret_cast<intptr_t>(object_slot),
2338 field_index);
2339 PrintF(trace_scope_->file(),
2340 "%e ; [sp + %d]\n", value, input_offset);
2341 }
2342 AddObjectDoubleValue(value);
2343 return;
2344 }
2345
2346 case Translation::LITERAL: {
2347 Object* literal = ComputeLiteral(iterator->Next());
2348 if (trace_scope_ != NULL) {
2349 PrintF(trace_scope_->file(),
2350 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2351 reinterpret_cast<intptr_t>(object_slot),
2352 field_index);
2353 literal->ShortPrint(trace_scope_->file());
2354 PrintF(trace_scope_->file(),
2355 " ; literal\n");
2356 }
2357 intptr_t value = reinterpret_cast<intptr_t>(literal);
2358 AddObjectTaggedValue(value);
2359 return;
2360 }
2361
2362 case Translation::DUPLICATED_OBJECT: {
2363 int object_index = iterator->Next();
2364 if (trace_scope_ != NULL) {
2365 PrintF(trace_scope_->file(),
2366 " nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
2367 reinterpret_cast<intptr_t>(object_slot),
2368 field_index);
2369 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2370 PrintF(trace_scope_->file(),
2371 " ; duplicate of object #%d\n", object_index);
2372 }
2373 // Use the materialization marker value as a sentinel and fill in
2374 // the object after the deoptimized frame is built.
2375 intptr_t value = reinterpret_cast<intptr_t>(
2376 isolate_->heap()->arguments_marker());
2377 AddObjectDuplication(0, object_index);
2378 AddObjectTaggedValue(value);
2379 return;
2380 }
2381
2382 case Translation::ARGUMENTS_OBJECT:
2383 case Translation::CAPTURED_OBJECT: {
2384 int length = iterator->Next();
2385 bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
2386 if (trace_scope_ != NULL) {
2387 PrintF(trace_scope_->file(),
2388 " nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
2389 reinterpret_cast<intptr_t>(object_slot),
2390 field_index);
2391 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2392 PrintF(trace_scope_->file(),
2393 " ; object (length = %d, is_args = %d)\n", length, is_args);
2394 }
2395 // Use the materialization marker value as a sentinel and fill in
2396 // the object after the deoptimized frame is built.
2397 intptr_t value = reinterpret_cast<intptr_t>(
2398 isolate_->heap()->arguments_marker());
2399 AddObjectStart(0, length, is_args);
2400 AddObjectTaggedValue(value);
2401 // We save the object values on the side and materialize the actual
2402 // object after the deoptimized frame is built.
2403 int object_index = deferred_objects_.length() - 1;
2404 for (int i = 0; i < length; i++) {
2405 DoTranslateObject(iterator, object_index, i);
2406 }
2407 return;
2408 }
2409 }
2410
2411 FATAL("Unexpected translation opcode");
2412}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002413
2414
Ben Murdochb0fe1622011-05-05 13:52:32 +01002415void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
2416 int frame_index,
2417 unsigned output_offset) {
2418 disasm::NameConverter converter;
2419 // A GC-safe temporary placeholder that we can put in the output frame.
2420 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
2421
Ben Murdochb0fe1622011-05-05 13:52:32 +01002422 Translation::Opcode opcode =
2423 static_cast<Translation::Opcode>(iterator->Next());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002424
2425 switch (opcode) {
2426 case Translation::BEGIN:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002427 case Translation::JS_FRAME:
2428 case Translation::ARGUMENTS_ADAPTOR_FRAME:
2429 case Translation::CONSTRUCT_STUB_FRAME:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002430 case Translation::GETTER_STUB_FRAME:
2431 case Translation::SETTER_STUB_FRAME:
2432 case Translation::COMPILED_STUB_FRAME:
2433 FATAL("Unexpected translation opcode");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002434 return;
2435
2436 case Translation::REGISTER: {
2437 int input_reg = iterator->Next();
2438 intptr_t input_value = input_->GetRegister(input_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002439 if (trace_scope_ != NULL) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002440 PrintF(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002441 trace_scope_->file(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002442 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002443 output_[frame_index]->GetTop() + output_offset,
2444 output_offset,
2445 input_value,
2446 converter.NameOfCPURegister(input_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002447 reinterpret_cast<Object*>(input_value)->ShortPrint(
2448 trace_scope_->file());
2449 PrintF(trace_scope_->file(), "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002450 }
2451 output_[frame_index]->SetFrameSlot(output_offset, input_value);
2452 return;
2453 }
2454
2455 case Translation::INT32_REGISTER: {
2456 int input_reg = iterator->Next();
2457 intptr_t value = input_->GetRegister(input_reg);
2458 bool is_smi = Smi::IsValid(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002459 if (trace_scope_ != NULL) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002460 PrintF(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002461 trace_scope_->file(),
Ben Murdochb0fe1622011-05-05 13:52:32 +01002462 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
2463 output_[frame_index]->GetTop() + output_offset,
2464 output_offset,
2465 value,
2466 converter.NameOfCPURegister(input_reg),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002467 TraceValueType(is_smi));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002468 }
2469 if (is_smi) {
2470 intptr_t tagged_value =
2471 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2472 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2473 } else {
2474 // We save the untagged value on the side and store a GC-safe
2475 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002476 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2477 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002478 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2479 }
2480 return;
2481 }
2482
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002483 case Translation::UINT32_REGISTER: {
2484 int input_reg = iterator->Next();
2485 uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
2486 bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
2487 if (trace_scope_ != NULL) {
2488 PrintF(
2489 trace_scope_->file(),
2490 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
2491 " ; uint %s (%s)\n",
2492 output_[frame_index]->GetTop() + output_offset,
2493 output_offset,
2494 value,
2495 converter.NameOfCPURegister(input_reg),
2496 TraceValueType(is_smi));
2497 }
2498 if (is_smi) {
2499 intptr_t tagged_value =
2500 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2501 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2502 } else {
2503 // We save the untagged value on the side and store a GC-safe
2504 // temporary placeholder in the frame.
2505 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2506 static_cast<double>(static_cast<uint32_t>(value)));
2507 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2508 }
2509 return;
2510 }
2511
Ben Murdochb0fe1622011-05-05 13:52:32 +01002512 case Translation::DOUBLE_REGISTER: {
2513 int input_reg = iterator->Next();
2514 double value = input_->GetDoubleRegister(input_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002515 if (trace_scope_ != NULL) {
2516 PrintF(trace_scope_->file(),
2517 " 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002518 output_[frame_index]->GetTop() + output_offset,
2519 output_offset,
2520 value,
2521 DoubleRegister::AllocationIndexToString(input_reg));
2522 }
2523 // We save the untagged value on the side and store a GC-safe
2524 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002525 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002526 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2527 return;
2528 }
2529
2530 case Translation::STACK_SLOT: {
2531 int input_slot_index = iterator->Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002532 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002533 intptr_t input_value = input_->GetFrameSlot(input_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002534 if (trace_scope_ != NULL) {
2535 PrintF(trace_scope_->file(),
2536 " 0x%08" V8PRIxPTR ": ",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002537 output_[frame_index]->GetTop() + output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002538 PrintF(trace_scope_->file(),
2539 "[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002540 output_offset,
2541 input_value,
2542 input_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002543 reinterpret_cast<Object*>(input_value)->ShortPrint(
2544 trace_scope_->file());
2545 PrintF(trace_scope_->file(), "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002546 }
2547 output_[frame_index]->SetFrameSlot(output_offset, input_value);
2548 return;
2549 }
2550
2551 case Translation::INT32_STACK_SLOT: {
2552 int input_slot_index = iterator->Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002553 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002554 intptr_t value = input_->GetFrameSlot(input_offset);
2555 bool is_smi = Smi::IsValid(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002556 if (trace_scope_ != NULL) {
2557 PrintF(trace_scope_->file(),
2558 " 0x%08" V8PRIxPTR ": ",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002559 output_[frame_index]->GetTop() + output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002560 PrintF(trace_scope_->file(),
2561 "[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002562 output_offset,
2563 value,
2564 input_offset,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002565 TraceValueType(is_smi));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002566 }
2567 if (is_smi) {
2568 intptr_t tagged_value =
2569 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2570 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2571 } else {
2572 // We save the untagged value on the side and store a GC-safe
2573 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002574 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2575 static_cast<double>(static_cast<int32_t>(value)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002576 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2577 }
2578 return;
2579 }
2580
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002581 case Translation::UINT32_STACK_SLOT: {
2582 int input_slot_index = iterator->Next();
2583 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2584 uintptr_t value =
2585 static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
2586 bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
2587 if (trace_scope_ != NULL) {
2588 PrintF(trace_scope_->file(),
2589 " 0x%08" V8PRIxPTR ": ",
2590 output_[frame_index]->GetTop() + output_offset);
2591 PrintF(trace_scope_->file(),
2592 "[top + %d] <- %" V8PRIuPTR " ; [sp + %d] (uint32 %s)\n",
2593 output_offset,
2594 value,
2595 input_offset,
2596 TraceValueType(is_smi));
2597 }
2598 if (is_smi) {
2599 intptr_t tagged_value =
2600 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2601 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2602 } else {
2603 // We save the untagged value on the side and store a GC-safe
2604 // temporary placeholder in the frame.
2605 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2606 static_cast<double>(static_cast<uint32_t>(value)));
2607 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2608 }
2609 return;
2610 }
2611
Ben Murdochb0fe1622011-05-05 13:52:32 +01002612 case Translation::DOUBLE_STACK_SLOT: {
2613 int input_slot_index = iterator->Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002614 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002615 double value = input_->GetDoubleFrameSlot(input_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 if (trace_scope_ != NULL) {
2617 PrintF(trace_scope_->file(),
2618 " 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002619 output_[frame_index]->GetTop() + output_offset,
2620 output_offset,
2621 value,
2622 input_offset);
2623 }
2624 // We save the untagged value on the side and store a GC-safe
2625 // temporary placeholder in the frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002626 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002627 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2628 return;
2629 }
2630
2631 case Translation::LITERAL: {
2632 Object* literal = ComputeLiteral(iterator->Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002633 if (trace_scope_ != NULL) {
2634 PrintF(trace_scope_->file(),
2635 " 0x%08" V8PRIxPTR ": [top + %d] <- ",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002636 output_[frame_index]->GetTop() + output_offset,
2637 output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002638 literal->ShortPrint(trace_scope_->file());
2639 PrintF(trace_scope_->file(), " ; literal\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002640 }
2641 intptr_t value = reinterpret_cast<intptr_t>(literal);
2642 output_[frame_index]->SetFrameSlot(output_offset, value);
2643 return;
2644 }
2645
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002646 case Translation::DUPLICATED_OBJECT: {
2647 int object_index = iterator->Next();
2648 if (trace_scope_ != NULL) {
2649 PrintF(trace_scope_->file(),
2650 " 0x%08" V8PRIxPTR ": [top + %d] <- ",
Ben Murdochb0fe1622011-05-05 13:52:32 +01002651 output_[frame_index]->GetTop() + output_offset,
2652 output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002653 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2654 PrintF(trace_scope_->file(),
2655 " ; duplicate of object #%d\n", object_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002656 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002657 // Use the materialization marker value as a sentinel and fill in
2658 // the object after the deoptimized frame is built.
Steve Block44f0eee2011-05-26 01:26:41 +01002659 intptr_t value = reinterpret_cast<intptr_t>(
2660 isolate_->heap()->arguments_marker());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002661 AddObjectDuplication(output_[frame_index]->GetTop() + output_offset,
2662 object_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002663 output_[frame_index]->SetFrameSlot(output_offset, value);
2664 return;
2665 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002666
2667 case Translation::ARGUMENTS_OBJECT:
2668 case Translation::CAPTURED_OBJECT: {
2669 int length = iterator->Next();
2670 bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
2671 if (trace_scope_ != NULL) {
2672 PrintF(trace_scope_->file(),
2673 " 0x%08" V8PRIxPTR ": [top + %d] <- ",
2674 output_[frame_index]->GetTop() + output_offset,
2675 output_offset);
2676 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2677 PrintF(trace_scope_->file(),
2678 " ; object (length = %d, is_args = %d)\n", length, is_args);
2679 }
2680 // Use the materialization marker value as a sentinel and fill in
2681 // the object after the deoptimized frame is built.
2682 intptr_t value = reinterpret_cast<intptr_t>(
2683 isolate_->heap()->arguments_marker());
2684 AddObjectStart(output_[frame_index]->GetTop() + output_offset,
2685 length, is_args);
2686 output_[frame_index]->SetFrameSlot(output_offset, value);
2687 // We save the object values on the side and materialize the actual
2688 // object after the deoptimized frame is built.
2689 int object_index = deferred_objects_.length() - 1;
2690 for (int i = 0; i < length; i++) {
2691 DoTranslateObject(iterator, object_index, i);
2692 }
2693 return;
2694 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002695 }
2696}
2697
2698
Ben Murdochb0fe1622011-05-05 13:52:32 +01002699unsigned Deoptimizer::ComputeInputFrameSize() const {
2700 unsigned fixed_size = ComputeFixedSize(function_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002701 // The fp-to-sp delta already takes the context, constant pool pointer and the
2702 // function into account so we have to avoid double counting them.
2703 unsigned result = fixed_size + fp_to_sp_delta_ -
2704 StandardFrameConstants::kFixedFrameSizeFromFp;
2705 if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
2706 unsigned stack_slots = compiled_code_->stack_slots();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002707 unsigned outgoing_size = ComputeOutgoingArgumentSize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002708 CHECK(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002709 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002710 return result;
2711}
2712
2713
2714unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
2715 // The fixed part of the frame consists of the return address, frame
2716 // pointer, function, context, and all the incoming arguments.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002717 return ComputeIncomingArgumentSize(function) +
2718 StandardFrameConstants::kFixedFrameSize;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002719}
2720
2721
2722unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
2723 // The incoming arguments is the values for formal parameters and
2724 // the receiver. Every slot contains a pointer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002725 if (function->IsSmi()) {
2726 CHECK_EQ(Smi::cast(function), Smi::FromInt(StackFrame::STUB));
2727 return 0;
2728 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002729 unsigned arguments = function->shared()->formal_parameter_count() + 1;
2730 return arguments * kPointerSize;
2731}
2732
2733
2734unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
2735 DeoptimizationInputData* data = DeoptimizationInputData::cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002736 compiled_code_->deoptimization_data());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002737 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
2738 return height * kPointerSize;
2739}
2740
2741
2742Object* Deoptimizer::ComputeLiteral(int index) const {
2743 DeoptimizationInputData* data = DeoptimizationInputData::cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002744 compiled_code_->deoptimization_data());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002745 FixedArray* literals = data->LiteralArray();
2746 return literals->get(index);
2747}
2748
2749
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002750void Deoptimizer::AddObjectStart(intptr_t slot, int length, bool is_args) {
2751 ObjectMaterializationDescriptor object_desc(
2752 reinterpret_cast<Address>(slot), jsframe_count_, length, -1, is_args);
2753 deferred_objects_.Add(object_desc);
2754}
2755
2756
2757void Deoptimizer::AddObjectDuplication(intptr_t slot, int object_index) {
2758 ObjectMaterializationDescriptor object_desc(
2759 reinterpret_cast<Address>(slot), jsframe_count_, -1, object_index, false);
2760 deferred_objects_.Add(object_desc);
2761}
2762
2763
2764void Deoptimizer::AddObjectTaggedValue(intptr_t value) {
2765 deferred_objects_tagged_values_.Add(reinterpret_cast<Object*>(value));
2766}
2767
2768
2769void Deoptimizer::AddObjectDoubleValue(double value) {
2770 deferred_objects_tagged_values_.Add(isolate()->heap()->the_hole_value());
2771 HeapNumberMaterializationDescriptor<int> value_desc(
2772 deferred_objects_tagged_values_.length() - 1, value);
2773 deferred_objects_double_values_.Add(value_desc);
2774}
2775
2776
2777void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) {
2778 HeapNumberMaterializationDescriptor<Address> value_desc(
Ben Murdoch8b112d22011-06-08 16:22:53 +01002779 reinterpret_cast<Address>(slot_address), value);
2780 deferred_heap_numbers_.Add(value_desc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002781}
2782
2783
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002784void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
2785 BailoutType type,
2786 int max_entry_id) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002787 // We cannot run this if the serializer is enabled because this will
2788 // cause us to emit relocation information for the external
2789 // references. This is fine because the deoptimizer's code section
2790 // isn't meant to be serialized at all.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002791 CHECK(type == EAGER || type == SOFT || type == LAZY);
2792 DeoptimizerData* data = isolate->deoptimizer_data();
2793 int entry_count = data->deopt_entry_code_entries_[type];
2794 if (max_entry_id < entry_count) return;
2795 entry_count = Max(entry_count, Deoptimizer::kMinNumberOfEntries);
2796 while (max_entry_id >= entry_count) entry_count *= 2;
2797 CHECK(entry_count <= Deoptimizer::kMaxNumberOfEntries);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002798
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002799 MacroAssembler masm(isolate, NULL, 16 * KB);
Steve Block44f0eee2011-05-26 01:26:41 +01002800 masm.set_emit_debug_code(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002801 GenerateDeoptimizationEntries(&masm, entry_count, type);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002802 CodeDesc desc;
2803 masm.GetCode(&desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002804 DCHECK(!RelocInfo::RequiresRelocation(desc));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002805
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002806 MemoryChunk* chunk = data->deopt_entry_code_[type];
2807 CHECK(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
2808 desc.instr_size);
2809 chunk->CommitArea(desc.instr_size);
2810 CopyBytes(chunk->area_start(), desc.buffer,
2811 static_cast<size_t>(desc.instr_size));
2812 CpuFeatures::FlushICache(chunk->area_start(), desc.instr_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002813
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002814 data->deopt_entry_code_entries_[type] = entry_count;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002815}
2816
2817
2818FrameDescription::FrameDescription(uint32_t frame_size,
2819 JSFunction* function)
2820 : frame_size_(frame_size),
2821 function_(function),
2822 top_(kZapUint32),
2823 pc_(kZapUint32),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002824 fp_(kZapUint32),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002825 context_(kZapUint32),
2826 constant_pool_(kZapUint32) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002827 // Zap all the registers.
2828 for (int r = 0; r < Register::kNumRegisters; r++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 // TODO(jbramley): It isn't safe to use kZapUint32 here. If the register
2830 // isn't used before the next safepoint, the GC will try to scan it as a
2831 // tagged value. kZapUint32 looks like a valid tagged pointer, but it isn't.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002832 SetRegister(r, kZapUint32);
2833 }
2834
2835 // Zap all the slots.
2836 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
2837 SetFrameSlot(o, kZapUint32);
2838 }
2839}
2840
2841
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002842int FrameDescription::ComputeFixedSize() {
2843 return StandardFrameConstants::kFixedFrameSize +
2844 (ComputeParametersCount() + 1) * kPointerSize;
2845}
2846
2847
2848unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002849 if (slot_index >= 0) {
2850 // Local or spill slots. Skip the fixed part of the frame
2851 // including all arguments.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002852 unsigned base = GetFrameSize() - ComputeFixedSize();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002853 return base - ((slot_index + 1) * kPointerSize);
2854 } else {
2855 // Incoming parameter.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002856 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
2857 unsigned base = GetFrameSize() - arg_size;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002858 return base - ((slot_index + 1) * kPointerSize);
2859 }
2860}
2861
2862
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002863int FrameDescription::ComputeParametersCount() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002864 switch (type_) {
2865 case StackFrame::JAVA_SCRIPT:
2866 return function_->shared()->formal_parameter_count();
2867 case StackFrame::ARGUMENTS_ADAPTOR: {
2868 // Last slot contains number of incomming arguments as a smi.
2869 // Can't use GetExpression(0) because it would cause infinite recursion.
2870 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value();
2871 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002872 case StackFrame::STUB:
2873 return -1; // Minus receiver.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002874 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002875 FATAL("Unexpected stack frame type");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002876 return 0;
2877 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002878}
2879
2880
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002881Object* FrameDescription::GetParameter(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002882 CHECK_GE(index, 0);
2883 CHECK_LT(index, ComputeParametersCount());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002884 // The slot indexes for incoming arguments are negative.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002885 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002886 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
2887}
2888
2889
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002890unsigned FrameDescription::GetExpressionCount() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002891 CHECK_EQ(StackFrame::JAVA_SCRIPT, type_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002892 unsigned size = GetFrameSize() - ComputeFixedSize();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002893 return size / kPointerSize;
2894}
2895
2896
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002897Object* FrameDescription::GetExpression(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002898 DCHECK_EQ(StackFrame::JAVA_SCRIPT, type_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002899 unsigned offset = GetOffsetFromSlotIndex(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002900 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
2901}
2902
2903
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002904void TranslationBuffer::Add(int32_t value, Zone* zone) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002905 // Encode the sign bit in the least significant bit.
2906 bool is_negative = (value < 0);
2907 uint32_t bits = ((is_negative ? -value : value) << 1) |
2908 static_cast<int32_t>(is_negative);
2909 // Encode the individual bytes using the least significant bit of
2910 // each byte to indicate whether or not more bytes follow.
2911 do {
2912 uint32_t next = bits >> 7;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002913 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002914 bits = next;
2915 } while (bits != 0);
2916}
2917
2918
2919int32_t TranslationIterator::Next() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002920 // Run through the bytes until we reach one with a least significant
2921 // bit of zero (marks the end).
2922 uint32_t bits = 0;
2923 for (int i = 0; true; i += 7) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002924 DCHECK(HasNext());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002925 uint8_t next = buffer_->get(index_++);
2926 bits |= (next >> 1) << i;
2927 if ((next & 1) == 0) break;
2928 }
2929 // The bits encode the sign in the least significant bit.
2930 bool is_negative = (bits & 1) == 1;
2931 int32_t result = bits >> 1;
2932 return is_negative ? -result : result;
2933}
2934
2935
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002936Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002937 int length = contents_.length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002938 Handle<ByteArray> result = factory->NewByteArray(length, TENURED);
2939 MemCopy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002940 return result;
2941}
2942
2943
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002944void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002945 buffer_->Add(CONSTRUCT_STUB_FRAME, zone());
2946 buffer_->Add(literal_id, zone());
2947 buffer_->Add(height, zone());
2948}
2949
2950
2951void Translation::BeginGetterStubFrame(int literal_id) {
2952 buffer_->Add(GETTER_STUB_FRAME, zone());
2953 buffer_->Add(literal_id, zone());
2954}
2955
2956
2957void Translation::BeginSetterStubFrame(int literal_id) {
2958 buffer_->Add(SETTER_STUB_FRAME, zone());
2959 buffer_->Add(literal_id, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002960}
2961
2962
2963void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002964 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone());
2965 buffer_->Add(literal_id, zone());
2966 buffer_->Add(height, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002967}
2968
2969
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002970void Translation::BeginJSFrame(BailoutId node_id,
2971 int literal_id,
2972 unsigned height) {
2973 buffer_->Add(JS_FRAME, zone());
2974 buffer_->Add(node_id.ToInt(), zone());
2975 buffer_->Add(literal_id, zone());
2976 buffer_->Add(height, zone());
2977}
2978
2979
2980void Translation::BeginCompiledStubFrame() {
2981 buffer_->Add(COMPILED_STUB_FRAME, zone());
2982}
2983
2984
2985void Translation::BeginArgumentsObject(int args_length) {
2986 buffer_->Add(ARGUMENTS_OBJECT, zone());
2987 buffer_->Add(args_length, zone());
2988}
2989
2990
2991void Translation::BeginCapturedObject(int length) {
2992 buffer_->Add(CAPTURED_OBJECT, zone());
2993 buffer_->Add(length, zone());
2994}
2995
2996
2997void Translation::DuplicateObject(int object_index) {
2998 buffer_->Add(DUPLICATED_OBJECT, zone());
2999 buffer_->Add(object_index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003000}
3001
3002
3003void Translation::StoreRegister(Register reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003004 buffer_->Add(REGISTER, zone());
3005 buffer_->Add(reg.code(), zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003006}
3007
3008
3009void Translation::StoreInt32Register(Register reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003010 buffer_->Add(INT32_REGISTER, zone());
3011 buffer_->Add(reg.code(), zone());
3012}
3013
3014
3015void Translation::StoreUint32Register(Register reg) {
3016 buffer_->Add(UINT32_REGISTER, zone());
3017 buffer_->Add(reg.code(), zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003018}
3019
3020
3021void Translation::StoreDoubleRegister(DoubleRegister reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003022 buffer_->Add(DOUBLE_REGISTER, zone());
3023 buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003024}
3025
3026
3027void Translation::StoreStackSlot(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003028 buffer_->Add(STACK_SLOT, zone());
3029 buffer_->Add(index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003030}
3031
3032
3033void Translation::StoreInt32StackSlot(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003034 buffer_->Add(INT32_STACK_SLOT, zone());
3035 buffer_->Add(index, zone());
3036}
3037
3038
3039void Translation::StoreUint32StackSlot(int index) {
3040 buffer_->Add(UINT32_STACK_SLOT, zone());
3041 buffer_->Add(index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003042}
3043
3044
3045void Translation::StoreDoubleStackSlot(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003046 buffer_->Add(DOUBLE_STACK_SLOT, zone());
3047 buffer_->Add(index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003048}
3049
3050
3051void Translation::StoreLiteral(int literal_id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003052 buffer_->Add(LITERAL, zone());
3053 buffer_->Add(literal_id, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003054}
3055
3056
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003057void Translation::StoreArgumentsObject(bool args_known,
3058 int args_index,
3059 int args_length) {
3060 buffer_->Add(ARGUMENTS_OBJECT, zone());
3061 buffer_->Add(args_known, zone());
3062 buffer_->Add(args_index, zone());
3063 buffer_->Add(args_length, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003064}
3065
3066
3067int Translation::NumberOfOperandsFor(Opcode opcode) {
3068 switch (opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003069 case GETTER_STUB_FRAME:
3070 case SETTER_STUB_FRAME:
3071 case DUPLICATED_OBJECT:
Ben Murdochb0fe1622011-05-05 13:52:32 +01003072 case ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003073 case CAPTURED_OBJECT:
Ben Murdochb0fe1622011-05-05 13:52:32 +01003074 case REGISTER:
3075 case INT32_REGISTER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003076 case UINT32_REGISTER:
Ben Murdochb0fe1622011-05-05 13:52:32 +01003077 case DOUBLE_REGISTER:
3078 case STACK_SLOT:
3079 case INT32_STACK_SLOT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003080 case UINT32_STACK_SLOT:
Ben Murdochb0fe1622011-05-05 13:52:32 +01003081 case DOUBLE_STACK_SLOT:
3082 case LITERAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003083 case COMPILED_STUB_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +01003084 return 1;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003085 case BEGIN:
3086 case ARGUMENTS_ADAPTOR_FRAME:
3087 case CONSTRUCT_STUB_FRAME:
3088 return 2;
3089 case JS_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +01003090 return 3;
3091 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003092 FATAL("Unexpected translation type");
Ben Murdochb0fe1622011-05-05 13:52:32 +01003093 return -1;
3094}
3095
3096
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003097#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
Ben Murdochb0fe1622011-05-05 13:52:32 +01003098
3099const char* Translation::StringFor(Opcode opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003100#define TRANSLATION_OPCODE_CASE(item) case item: return #item;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003101 switch (opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003102 TRANSLATION_OPCODE_LIST(TRANSLATION_OPCODE_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01003103 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003104#undef TRANSLATION_OPCODE_CASE
Ben Murdochb0fe1622011-05-05 13:52:32 +01003105 UNREACHABLE();
3106 return "";
3107}
3108
3109#endif
3110
3111
Ben Murdoch8b112d22011-06-08 16:22:53 +01003112// We can't intermix stack decoding and allocations because
3113// deoptimization infrastracture is not GC safe.
3114// Thus we build a temporary structure in malloced space.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003115SlotRef SlotRefValueBuilder::ComputeSlotForNextArgument(
3116 Translation::Opcode opcode,
3117 TranslationIterator* iterator,
3118 DeoptimizationInputData* data,
3119 JavaScriptFrame* frame) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003120 switch (opcode) {
3121 case Translation::BEGIN:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003122 case Translation::JS_FRAME:
3123 case Translation::ARGUMENTS_ADAPTOR_FRAME:
3124 case Translation::CONSTRUCT_STUB_FRAME:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003125 case Translation::GETTER_STUB_FRAME:
3126 case Translation::SETTER_STUB_FRAME:
Ben Murdoch8b112d22011-06-08 16:22:53 +01003127 // Peeled off before getting here.
3128 break;
3129
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003130 case Translation::DUPLICATED_OBJECT: {
3131 return SlotRef::NewDuplicateObject(iterator->Next());
3132 }
3133
Ben Murdoch8b112d22011-06-08 16:22:53 +01003134 case Translation::ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003135 return SlotRef::NewArgumentsObject(iterator->Next());
3136
3137 case Translation::CAPTURED_OBJECT: {
3138 return SlotRef::NewDeferredObject(iterator->Next());
3139 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003140
3141 case Translation::REGISTER:
3142 case Translation::INT32_REGISTER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003143 case Translation::UINT32_REGISTER:
Ben Murdoch8b112d22011-06-08 16:22:53 +01003144 case Translation::DOUBLE_REGISTER:
Ben Murdoch8b112d22011-06-08 16:22:53 +01003145 // We are at safepoint which corresponds to call. All registers are
3146 // saved by caller so there would be no live registers at this
3147 // point. Thus these translation commands should not be used.
3148 break;
3149
3150 case Translation::STACK_SLOT: {
3151 int slot_index = iterator->Next();
3152 Address slot_addr = SlotAddress(frame, slot_index);
3153 return SlotRef(slot_addr, SlotRef::TAGGED);
3154 }
3155
3156 case Translation::INT32_STACK_SLOT: {
3157 int slot_index = iterator->Next();
3158 Address slot_addr = SlotAddress(frame, slot_index);
3159 return SlotRef(slot_addr, SlotRef::INT32);
3160 }
3161
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003162 case Translation::UINT32_STACK_SLOT: {
3163 int slot_index = iterator->Next();
3164 Address slot_addr = SlotAddress(frame, slot_index);
3165 return SlotRef(slot_addr, SlotRef::UINT32);
3166 }
3167
Ben Murdoch8b112d22011-06-08 16:22:53 +01003168 case Translation::DOUBLE_STACK_SLOT: {
3169 int slot_index = iterator->Next();
3170 Address slot_addr = SlotAddress(frame, slot_index);
3171 return SlotRef(slot_addr, SlotRef::DOUBLE);
3172 }
3173
3174 case Translation::LITERAL: {
3175 int literal_index = iterator->Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003176 return SlotRef(data->GetIsolate(),
3177 data->LiteralArray()->get(literal_index));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003178 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003179
3180 case Translation::COMPILED_STUB_FRAME:
3181 UNREACHABLE();
3182 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01003183 }
3184
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003185 FATAL("We should never get here - unexpected deopt info.");
Ben Murdoch8b112d22011-06-08 16:22:53 +01003186 return SlotRef();
3187}
3188
3189
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003190SlotRefValueBuilder::SlotRefValueBuilder(JavaScriptFrame* frame,
3191 int inlined_jsframe_index,
3192 int formal_parameter_count)
3193 : current_slot_(0), args_length_(-1), first_slot_index_(-1) {
3194 DisallowHeapAllocation no_gc;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003195
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003196 int deopt_index = Safepoint::kNoDeoptimizationIndex;
Ben Murdoch8b112d22011-06-08 16:22:53 +01003197 DeoptimizationInputData* data =
3198 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
3199 TranslationIterator it(data->TranslationByteArray(),
3200 data->TranslationIndex(deopt_index)->value());
3201 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003202 CHECK_EQ(opcode, Translation::BEGIN);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003203 it.Next(); // Drop frame count.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003204
3205 stack_frame_id_ = frame->fp();
3206
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003207 int jsframe_count = it.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003208 CHECK_GT(jsframe_count, inlined_jsframe_index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003209 int jsframes_to_skip = inlined_jsframe_index;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003210 int number_of_slots = -1; // Number of slots inside our frame (yet unknown)
3211 bool should_deopt = false;
3212 while (number_of_slots != 0) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003213 opcode = static_cast<Translation::Opcode>(it.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003214 bool processed = false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003215 if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) {
3216 if (jsframes_to_skip == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003217 CHECK_EQ(Translation::NumberOfOperandsFor(opcode), 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003218
3219 it.Skip(1); // literal id
3220 int height = it.Next();
3221
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003222 // Skip the translation command for the receiver.
3223 it.Skip(Translation::NumberOfOperandsFor(
3224 static_cast<Translation::Opcode>(it.Next())));
3225
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003226 // We reached the arguments adaptor frame corresponding to the
3227 // inlined function in question. Number of arguments is height - 1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003228 first_slot_index_ = slot_refs_.length();
3229 args_length_ = height - 1;
3230 number_of_slots = height - 1;
3231 processed = true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003232 }
3233 } else if (opcode == Translation::JS_FRAME) {
3234 if (jsframes_to_skip == 0) {
3235 // Skip over operands to advance to the next opcode.
3236 it.Skip(Translation::NumberOfOperandsFor(opcode));
3237
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003238 // Skip the translation command for the receiver.
3239 it.Skip(Translation::NumberOfOperandsFor(
3240 static_cast<Translation::Opcode>(it.Next())));
3241
Ben Murdoch85b71792012-04-11 18:30:58 +01003242 // We reached the frame corresponding to the inlined function
3243 // in question. Process the translation commands for the
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003244 // arguments. Number of arguments is equal to the number of
3245 // format parameter count.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003246 first_slot_index_ = slot_refs_.length();
3247 args_length_ = formal_parameter_count;
3248 number_of_slots = formal_parameter_count;
3249 processed = true;
Ben Murdoch85b71792012-04-11 18:30:58 +01003250 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003251 jsframes_to_skip--;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003252 } else if (opcode != Translation::BEGIN &&
3253 opcode != Translation::CONSTRUCT_STUB_FRAME &&
3254 opcode != Translation::GETTER_STUB_FRAME &&
3255 opcode != Translation::SETTER_STUB_FRAME &&
3256 opcode != Translation::COMPILED_STUB_FRAME) {
3257 slot_refs_.Add(ComputeSlotForNextArgument(opcode, &it, data, frame));
3258
3259 if (first_slot_index_ >= 0) {
3260 // We have found the beginning of our frame -> make sure we count
3261 // the nested slots of captured objects
3262 number_of_slots--;
3263 SlotRef& slot = slot_refs_.last();
3264 CHECK_NE(slot.Representation(), SlotRef::ARGUMENTS_OBJECT);
3265 number_of_slots += slot.GetChildrenCount();
3266 if (slot.Representation() == SlotRef::DEFERRED_OBJECT ||
3267 slot.Representation() == SlotRef::DUPLICATE_OBJECT) {
3268 should_deopt = true;
3269 }
3270 }
3271
3272 processed = true;
Ben Murdoch85b71792012-04-11 18:30:58 +01003273 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003274 if (!processed) {
3275 // Skip over operands to advance to the next opcode.
3276 it.Skip(Translation::NumberOfOperandsFor(opcode));
3277 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003278 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003279 if (should_deopt) {
3280 List<JSFunction*> functions(2);
3281 frame->GetFunctions(&functions);
3282 Deoptimizer::DeoptimizeFunction(functions[0]);
3283 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003284}
3285
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003286
3287Handle<Object> SlotRef::GetValue(Isolate* isolate) {
3288 switch (representation_) {
3289 case TAGGED:
3290 return Handle<Object>(Memory::Object_at(addr_), isolate);
3291
3292 case INT32: {
3293#if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
3294 int value = Memory::int32_at(addr_ + kIntSize);
3295#else
3296 int value = Memory::int32_at(addr_);
3297#endif
3298 if (Smi::IsValid(value)) {
3299 return Handle<Object>(Smi::FromInt(value), isolate);
3300 } else {
3301 return isolate->factory()->NewNumberFromInt(value);
3302 }
3303 }
3304
3305 case UINT32: {
3306#if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
3307 uint32_t value = Memory::uint32_at(addr_ + kIntSize);
3308#else
3309 uint32_t value = Memory::uint32_at(addr_);
3310#endif
3311 if (value <= static_cast<uint32_t>(Smi::kMaxValue)) {
3312 return Handle<Object>(Smi::FromInt(static_cast<int>(value)), isolate);
3313 } else {
3314 return isolate->factory()->NewNumber(static_cast<double>(value));
3315 }
3316 }
3317
3318 case DOUBLE: {
3319 double value = read_double_value(addr_);
3320 return isolate->factory()->NewNumber(value);
3321 }
3322
3323 case LITERAL:
3324 return literal_;
3325
3326 default:
3327 FATAL("We should never get here - unexpected deopt info.");
3328 return Handle<Object>::null();
3329 }
3330}
3331
3332
3333void SlotRefValueBuilder::Prepare(Isolate* isolate) {
3334 MaterializedObjectStore* materialized_store =
3335 isolate->materialized_object_store();
3336 previously_materialized_objects_ = materialized_store->Get(stack_frame_id_);
3337 prev_materialized_count_ = previously_materialized_objects_.is_null()
3338 ? 0 : previously_materialized_objects_->length();
3339
3340 // Skip any materialized objects of the inlined "parent" frames.
3341 // (Note that we still need to materialize them because they might be
3342 // referred to as duplicated objects.)
3343 while (current_slot_ < first_slot_index_) {
3344 GetNext(isolate, 0);
3345 }
3346 CHECK_EQ(current_slot_, first_slot_index_);
3347}
3348
3349
3350Handle<Object> SlotRefValueBuilder::GetPreviouslyMaterialized(
3351 Isolate* isolate, int length) {
3352 int object_index = materialized_objects_.length();
3353 Handle<Object> return_value = Handle<Object>(
3354 previously_materialized_objects_->get(object_index), isolate);
3355 materialized_objects_.Add(return_value);
3356
3357 // Now need to skip all the nested objects (and possibly read them from
3358 // the materialization store, too).
3359 for (int i = 0; i < length; i++) {
3360 SlotRef& slot = slot_refs_[current_slot_];
3361 current_slot_++;
3362
3363 // We need to read all the nested objects - add them to the
3364 // number of objects we need to process.
3365 length += slot.GetChildrenCount();
3366
3367 // Put the nested deferred/duplicate objects into our materialization
3368 // array.
3369 if (slot.Representation() == SlotRef::DEFERRED_OBJECT ||
3370 slot.Representation() == SlotRef::DUPLICATE_OBJECT) {
3371 int nested_object_index = materialized_objects_.length();
3372 Handle<Object> nested_object = Handle<Object>(
3373 previously_materialized_objects_->get(nested_object_index),
3374 isolate);
3375 materialized_objects_.Add(nested_object);
3376 }
3377 }
3378
3379 return return_value;
3380}
3381
3382
3383Handle<Object> SlotRefValueBuilder::GetNext(Isolate* isolate, int lvl) {
3384 SlotRef& slot = slot_refs_[current_slot_];
3385 current_slot_++;
3386 switch (slot.Representation()) {
3387 case SlotRef::TAGGED:
3388 case SlotRef::INT32:
3389 case SlotRef::UINT32:
3390 case SlotRef::DOUBLE:
3391 case SlotRef::LITERAL: {
3392 return slot.GetValue(isolate);
3393 }
3394 case SlotRef::ARGUMENTS_OBJECT: {
3395 // We should never need to materialize an arguments object,
3396 // but we still need to put something into the array
3397 // so that the indexing is consistent.
3398 materialized_objects_.Add(isolate->factory()->undefined_value());
3399 int length = slot.GetChildrenCount();
3400 for (int i = 0; i < length; ++i) {
3401 // We don't need the argument, just ignore it
3402 GetNext(isolate, lvl + 1);
3403 }
3404 return isolate->factory()->undefined_value();
3405 }
3406 case SlotRef::DEFERRED_OBJECT: {
3407 int length = slot.GetChildrenCount();
3408 CHECK(slot_refs_[current_slot_].Representation() == SlotRef::LITERAL ||
3409 slot_refs_[current_slot_].Representation() == SlotRef::TAGGED);
3410
3411 int object_index = materialized_objects_.length();
3412 if (object_index < prev_materialized_count_) {
3413 return GetPreviouslyMaterialized(isolate, length);
3414 }
3415
3416 Handle<Object> map_object = slot_refs_[current_slot_].GetValue(isolate);
3417 Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
3418 Handle<Map>::cast(map_object));
3419 current_slot_++;
3420 // TODO(jarin) this should be unified with the code in
3421 // Deoptimizer::MaterializeNextHeapObject()
3422 switch (map->instance_type()) {
3423 case MUTABLE_HEAP_NUMBER_TYPE:
3424 case HEAP_NUMBER_TYPE: {
3425 // Reuse the HeapNumber value directly as it is already properly
3426 // tagged and skip materializing the HeapNumber explicitly.
3427 Handle<Object> object = GetNext(isolate, lvl + 1);
3428 materialized_objects_.Add(object);
3429 // On 32-bit architectures, there is an extra slot there because
3430 // the escape analysis calculates the number of slots as
3431 // object-size/pointer-size. To account for this, we read out
3432 // any extra slots.
3433 for (int i = 0; i < length - 2; i++) {
3434 GetNext(isolate, lvl + 1);
3435 }
3436 return object;
3437 }
3438 case JS_OBJECT_TYPE: {
3439 Handle<JSObject> object =
3440 isolate->factory()->NewJSObjectFromMap(map, NOT_TENURED, false);
3441 materialized_objects_.Add(object);
3442 Handle<Object> properties = GetNext(isolate, lvl + 1);
3443 Handle<Object> elements = GetNext(isolate, lvl + 1);
3444 object->set_properties(FixedArray::cast(*properties));
3445 object->set_elements(FixedArrayBase::cast(*elements));
3446 for (int i = 0; i < length - 3; ++i) {
3447 Handle<Object> value = GetNext(isolate, lvl + 1);
3448 FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
3449 object->FastPropertyAtPut(index, *value);
3450 }
3451 return object;
3452 }
3453 case JS_ARRAY_TYPE: {
3454 Handle<JSArray> object =
3455 isolate->factory()->NewJSArray(0, map->elements_kind());
3456 materialized_objects_.Add(object);
3457 Handle<Object> properties = GetNext(isolate, lvl + 1);
3458 Handle<Object> elements = GetNext(isolate, lvl + 1);
3459 Handle<Object> length = GetNext(isolate, lvl + 1);
3460 object->set_properties(FixedArray::cast(*properties));
3461 object->set_elements(FixedArrayBase::cast(*elements));
3462 object->set_length(*length);
3463 return object;
3464 }
3465 default:
3466 PrintF(stderr,
3467 "[couldn't handle instance type %d]\n", map->instance_type());
3468 UNREACHABLE();
3469 break;
3470 }
3471 UNREACHABLE();
3472 break;
3473 }
3474
3475 case SlotRef::DUPLICATE_OBJECT: {
3476 int object_index = slot.DuplicateObjectId();
3477 Handle<Object> object = materialized_objects_[object_index];
3478 materialized_objects_.Add(object);
3479 return object;
3480 }
3481 default:
3482 UNREACHABLE();
3483 break;
3484 }
3485
3486 FATAL("We should never get here - unexpected deopt slot kind.");
3487 return Handle<Object>::null();
3488}
3489
3490
3491void SlotRefValueBuilder::Finish(Isolate* isolate) {
3492 // We should have processed all the slots
3493 CHECK_EQ(slot_refs_.length(), current_slot_);
3494
3495 if (materialized_objects_.length() > prev_materialized_count_) {
3496 // We have materialized some new objects, so we have to store them
3497 // to prevent duplicate materialization
3498 Handle<FixedArray> array = isolate->factory()->NewFixedArray(
3499 materialized_objects_.length());
3500 for (int i = 0; i < materialized_objects_.length(); i++) {
3501 array->set(i, *(materialized_objects_.at(i)));
3502 }
3503 isolate->materialized_object_store()->Set(stack_frame_id_, array);
3504 }
3505}
3506
3507
3508Handle<FixedArray> MaterializedObjectStore::Get(Address fp) {
3509 int index = StackIdToIndex(fp);
3510 if (index == -1) {
3511 return Handle<FixedArray>::null();
3512 }
3513 Handle<FixedArray> array = GetStackEntries();
3514 CHECK_GT(array->length(), index);
3515 return Handle<FixedArray>::cast(Handle<Object>(array->get(index),
3516 isolate()));
3517}
3518
3519
3520void MaterializedObjectStore::Set(Address fp,
3521 Handle<FixedArray> materialized_objects) {
3522 int index = StackIdToIndex(fp);
3523 if (index == -1) {
3524 index = frame_fps_.length();
3525 frame_fps_.Add(fp);
3526 }
3527
3528 Handle<FixedArray> array = EnsureStackEntries(index + 1);
3529 array->set(index, *materialized_objects);
3530}
3531
3532
3533void MaterializedObjectStore::Remove(Address fp) {
3534 int index = StackIdToIndex(fp);
3535 CHECK_GE(index, 0);
3536
3537 frame_fps_.Remove(index);
3538 Handle<FixedArray> array = GetStackEntries();
3539 CHECK_LT(index, array->length());
3540 for (int i = index; i < frame_fps_.length(); i++) {
3541 array->set(i, array->get(i + 1));
3542 }
3543 array->set(frame_fps_.length(), isolate()->heap()->undefined_value());
3544}
3545
3546
3547int MaterializedObjectStore::StackIdToIndex(Address fp) {
3548 for (int i = 0; i < frame_fps_.length(); i++) {
3549 if (frame_fps_[i] == fp) {
3550 return i;
3551 }
3552 }
3553 return -1;
3554}
3555
3556
3557Handle<FixedArray> MaterializedObjectStore::GetStackEntries() {
3558 return Handle<FixedArray>(isolate()->heap()->materialized_objects());
3559}
3560
3561
3562Handle<FixedArray> MaterializedObjectStore::EnsureStackEntries(int length) {
3563 Handle<FixedArray> array = GetStackEntries();
3564 if (array->length() >= length) {
3565 return array;
3566 }
3567
3568 int new_length = length > 10 ? length : 10;
3569 if (new_length < 2 * array->length()) {
3570 new_length = 2 * array->length();
3571 }
3572
3573 Handle<FixedArray> new_array =
3574 isolate()->factory()->NewFixedArray(new_length, TENURED);
3575 for (int i = 0; i < array->length(); i++) {
3576 new_array->set(i, array->get(i));
3577 }
3578 for (int i = array->length(); i < length; i++) {
3579 new_array->set(i, isolate()->heap()->undefined_value());
3580 }
3581 isolate()->heap()->public_set_materialized_objects(*new_array);
3582 return new_array;
3583}
3584
Ben Murdoch8b112d22011-06-08 16:22:53 +01003585
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003586DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
3587 int frame_index,
3588 bool has_arguments_adaptor,
3589 bool has_construct_stub) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003590 FrameDescription* output_frame = deoptimizer->output_[frame_index];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003591 function_ = output_frame->GetFunction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003592 context_ = reinterpret_cast<Object*>(output_frame->GetContext());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003593 has_construct_stub_ = has_construct_stub;
3594 expression_count_ = output_frame->GetExpressionCount();
3595 expression_stack_ = new Object*[expression_count_];
3596 // Get the source position using the unoptimized code.
3597 Address pc = reinterpret_cast<Address>(output_frame->GetPc());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003598 Code* code = Code::cast(deoptimizer->isolate()->FindCodeObject(pc));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003599 source_position_ = code->SourcePosition(pc);
3600
3601 for (int i = 0; i < expression_count_; i++) {
3602 SetExpression(i, output_frame->GetExpression(i));
3603 }
3604
3605 if (has_arguments_adaptor) {
3606 output_frame = deoptimizer->output_[frame_index - 1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003607 CHECK_EQ(output_frame->GetFrameType(), StackFrame::ARGUMENTS_ADAPTOR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003608 }
3609
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003610 parameters_count_ = output_frame->ComputeParametersCount();
3611 parameters_ = new Object*[parameters_count_];
3612 for (int i = 0; i < parameters_count_; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003613 SetParameter(i, output_frame->GetParameter(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003614 }
3615}
3616
3617
3618DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
3619 delete[] expression_stack_;
3620 delete[] parameters_;
3621}
3622
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003623
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003624void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003625 v->VisitPointer(bit_cast<Object**>(&function_));
3626 v->VisitPointer(&context_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003627 v->VisitPointers(parameters_, parameters_ + parameters_count_);
3628 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
3629}
3630
Ben Murdochb0fe1622011-05-05 13:52:32 +01003631} } // namespace v8::internal