blob: e00e5ab538a220a2244347d3c5fa3ba0f53eaccc [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 Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/deoptimizer.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +01006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/accessors.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/ast/prettyprinter.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/disasm.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/frames-inl.h"
12#include "src/full-codegen/full-codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/global-handles.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010014#include "src/interpreter/interpreter.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/macro-assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016#include "src/profiler/cpu-profiler.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010017#include "src/tracing/trace-event.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018#include "src/v8.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010019
20
21namespace v8 {
22namespace internal {
23
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024static MemoryChunk* AllocateCodeChunk(MemoryAllocator* allocator) {
25 return allocator->AllocateChunk(Deoptimizer::GetMaxDeoptTableSize(),
26 base::OS::CommitPageSize(),
27#if defined(__native_client__)
28 // The Native Client port of V8 uses an interpreter,
29 // so code pages don't need PROT_EXEC.
30 NOT_EXECUTABLE,
31#else
32 EXECUTABLE,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000033#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034 NULL);
35}
36
37
38DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator)
39 : allocator_(allocator),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040 current_(NULL) {
41 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
42 deopt_entry_code_entries_[i] = -1;
43 deopt_entry_code_[i] = AllocateCodeChunk(allocator);
44 }
Steve Block44f0eee2011-05-26 01:26:41 +010045}
Ben Murdochb0fe1622011-05-05 13:52:32 +010046
47
Steve Block44f0eee2011-05-26 01:26:41 +010048DeoptimizerData::~DeoptimizerData() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
50 allocator_->Free(deopt_entry_code_[i]);
51 deopt_entry_code_[i] = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +010052 }
53}
54
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000055
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056Code* Deoptimizer::FindDeoptimizingCode(Address addr) {
57 if (function_->IsHeapObject()) {
58 // Search all deoptimizing code in the native context of the function.
59 Context* native_context = function_->context()->native_context();
60 Object* element = native_context->DeoptimizedCodeListHead();
61 while (!element->IsUndefined()) {
62 Code* code = Code::cast(element);
63 CHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
64 if (code->contains(addr)) return code;
65 element = code->next_code_link();
66 }
67 }
68 return NULL;
69}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000070
71
Ben Murdoch3ef787d2012-04-12 10:51:47 +010072// We rely on this function not causing a GC. It is called from generated code
73// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +010074Deoptimizer* Deoptimizer::New(JSFunction* function,
75 BailoutType type,
76 unsigned bailout_id,
77 Address from,
Steve Block44f0eee2011-05-26 01:26:41 +010078 int fp_to_sp_delta,
79 Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +010080 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
81 function,
82 type,
83 bailout_id,
84 from,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000085 fp_to_sp_delta,
86 NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 CHECK(isolate->deoptimizer_data()->current_ == NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010088 isolate->deoptimizer_data()->current_ = deoptimizer;
Ben Murdochb0fe1622011-05-05 13:52:32 +010089 return deoptimizer;
90}
91
92
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093// No larger than 2K on all platforms
94static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
95
96
97size_t Deoptimizer::GetMaxDeoptTableSize() {
98 int entries_size =
99 Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
100 int commit_page_size = static_cast<int>(base::OS::CommitPageSize());
101 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
102 commit_page_size) + 1;
103 return static_cast<size_t>(commit_page_size * page_count);
104}
105
106
Steve Block44f0eee2011-05-26 01:26:41 +0100107Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +0100108 Deoptimizer* result = isolate->deoptimizer_data()->current_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 CHECK_NOT_NULL(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100110 result->DeleteFrameDescriptions();
Steve Block44f0eee2011-05-26 01:26:41 +0100111 isolate->deoptimizer_data()->current_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100112 return result;
113}
114
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100115
116int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) {
117 if (jsframe_index == 0) return 0;
118
119 int frame_index = 0;
120 while (jsframe_index >= 0) {
121 FrameDescription* frame = output_[frame_index];
122 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) {
123 jsframe_index--;
124 }
125 frame_index++;
126 }
127
128 return frame_index - 1;
129}
130
131
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000132DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
133 JavaScriptFrame* frame,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100134 int jsframe_index,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000135 Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 CHECK(frame->is_optimized());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000137
Ben Murdoch097c5b22016-05-18 11:27:45 +0100138 TranslatedState translated_values(frame);
139 translated_values.Prepare(false, frame->fp());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000140
Ben Murdoch097c5b22016-05-18 11:27:45 +0100141 TranslatedState::iterator frame_it = translated_values.end();
142 int counter = jsframe_index;
143 for (auto it = translated_values.begin(); it != translated_values.end();
144 it++) {
145 if (it->kind() == TranslatedFrame::kFunction ||
146 it->kind() == TranslatedFrame::kInterpretedFunction) {
147 if (counter == 0) {
148 frame_it = it;
149 break;
150 }
151 counter--;
152 }
153 }
154 CHECK(frame_it != translated_values.end());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000155
Ben Murdoch097c5b22016-05-18 11:27:45 +0100156 DeoptimizedFrameInfo* info =
157 new DeoptimizedFrameInfo(&translated_values, frame_it, isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000158
159 return info;
160}
161
162
163void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
164 Isolate* isolate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000165 delete info;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000166}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167
Ben Murdochb0fe1622011-05-05 13:52:32 +0100168
169void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
170 int count,
171 BailoutType type) {
172 TableEntryGenerator generator(masm, type, count);
173 generator.Generate();
174}
175
176
Ben Murdochb0fe1622011-05-05 13:52:32 +0100177void Deoptimizer::VisitAllOptimizedFunctionsForContext(
178 Context* context, OptimizedFunctionVisitor* visitor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100180
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181 CHECK(context->IsNativeContext());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100182
183 visitor->EnterContext(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184
185 // Visit the list of optimized functions, removing elements that
186 // no longer refer to optimized code.
187 JSFunction* prev = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100188 Object* element = context->OptimizedFunctionsListHead();
189 while (!element->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 JSFunction* function = JSFunction::cast(element);
191 Object* next = function->next_function_link();
192 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION ||
193 (visitor->VisitFunction(function),
194 function->code()->kind() != Code::OPTIMIZED_FUNCTION)) {
195 // The function no longer refers to optimized code, or the visitor
196 // changed the code to which it refers to no longer be optimized code.
197 // Remove the function from this list.
198 if (prev != NULL) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199 prev->set_next_function_link(next, UPDATE_WEAK_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 } else {
201 context->SetOptimizedFunctionsListHead(next);
202 }
203 // The visitor should not alter the link directly.
204 CHECK_EQ(function->next_function_link(), next);
205 // Set the next function link to undefined to indicate it is no longer
206 // in the optimized functions list.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 function->set_next_function_link(context->GetHeap()->undefined_value(),
208 SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209 } else {
210 // The visitor should not alter the link directly.
211 CHECK_EQ(function->next_function_link(), next);
212 // preserve this element.
213 prev = function;
214 }
215 element = next;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100216 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217
Ben Murdochb0fe1622011-05-05 13:52:32 +0100218 visitor->LeaveContext(context);
219}
220
221
Ben Murdochb0fe1622011-05-05 13:52:32 +0100222void Deoptimizer::VisitAllOptimizedFunctions(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 Isolate* isolate,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100224 OptimizedFunctionVisitor* visitor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 // Run through the list of all native contexts.
228 Object* context = isolate->heap()->native_contexts_list();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100229 while (!context->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000230 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100231 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100232 }
233}
234
235
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236// Unlink functions referring to code marked for deoptimization, then move
237// marked code from the optimized code list to the deoptimized code list,
238// and patch code for lazy deopt.
239void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
240 DisallowHeapAllocation no_allocation;
241
242 // A "closure" that unlinks optimized code that is going to be
243 // deoptimized from the functions that refer to it.
244 class SelectedCodeUnlinker: public OptimizedFunctionVisitor {
245 public:
246 virtual void EnterContext(Context* context) { } // Don't care.
247 virtual void LeaveContext(Context* context) { } // Don't care.
248 virtual void VisitFunction(JSFunction* function) {
249 Code* code = function->code();
250 if (!code->marked_for_deoptimization()) return;
251
252 // Unlink this function and evict from optimized code map.
253 SharedFunctionInfo* shared = function->shared();
254 function->set_code(shared->code());
255
256 if (FLAG_trace_deopt) {
257 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
258 PrintF(scope.file(), "[deoptimizer unlinked: ");
259 function->PrintName(scope.file());
260 PrintF(scope.file(),
261 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
262 }
263 }
264 };
265
266 // Unlink all functions that refer to marked code.
267 SelectedCodeUnlinker unlinker;
268 VisitAllOptimizedFunctionsForContext(context, &unlinker);
269
270 Isolate* isolate = context->GetHeap()->isolate();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100271#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272 Code* topmost_optimized_code = NULL;
273 bool safe_to_deopt_topmost_optimized_code = false;
274 // Make sure all activations of optimized code can deopt at their current PC.
275 // The topmost optimized code has special handling because it cannot be
276 // deoptimized due to weak object dependency.
277 for (StackFrameIterator it(isolate, isolate->thread_local_top());
278 !it.done(); it.Advance()) {
279 StackFrame::Type type = it.frame()->type();
280 if (type == StackFrame::OPTIMIZED) {
281 Code* code = it.frame()->LookupCode();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 JSFunction* function =
283 static_cast<OptimizedFrame*>(it.frame())->function();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 if (FLAG_trace_deopt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 CodeTracer::Scope scope(isolate->GetCodeTracer());
286 PrintF(scope.file(), "[deoptimizer found activation of function: ");
287 function->PrintName(scope.file());
288 PrintF(scope.file(),
289 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
290 }
291 SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
292 int deopt_index = safepoint.deoptimization_index();
293 // Turbofan deopt is checked when we are patching addresses on stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 bool turbofanned = code->is_turbofanned() &&
295 function->shared()->asm_function() &&
296 !FLAG_turbo_asm_deoptimization;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 bool safe_to_deopt =
298 deopt_index != Safepoint::kNoDeoptimizationIndex || turbofanned;
299 CHECK(topmost_optimized_code == NULL || safe_to_deopt || turbofanned);
300 if (topmost_optimized_code == NULL) {
301 topmost_optimized_code = code;
302 safe_to_deopt_topmost_optimized_code = safe_to_deopt;
303 }
304 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100305 }
306#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307
308 // Move marked code from the optimized code list to the deoptimized
309 // code list, collecting them into a ZoneList.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 ZoneList<Code*> codes(10, &zone);
312
313 // Walk over all optimized code objects in this native context.
314 Code* prev = NULL;
315 Object* element = context->OptimizedCodeListHead();
316 while (!element->IsUndefined()) {
317 Code* code = Code::cast(element);
318 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
319 Object* next = code->next_code_link();
320
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 if (code->marked_for_deoptimization()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 // Put the code into the list for later patching.
323 codes.Add(code, &zone);
324
325 if (prev != NULL) {
326 // Skip this code in the optimized code list.
327 prev->set_next_code_link(next);
328 } else {
329 // There was no previous node, the next node is the new head.
330 context->SetOptimizedCodeListHead(next);
331 }
332
333 // Move the code to the _deoptimized_ code list.
334 code->set_next_code_link(context->DeoptimizedCodeListHead());
335 context->SetDeoptimizedCodeListHead(code);
336 } else {
337 // Not marked; preserve this element.
338 prev = code;
339 }
340 element = next;
341 }
342
Ben Murdoch097c5b22016-05-18 11:27:45 +0100343 // We need a handle scope only because of the macro assembler,
344 // which is used in code patching in EnsureCodeForDeoptimizationEntry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 HandleScope scope(isolate);
346
347 // Now patch all the codes for deoptimization.
348 for (int i = 0; i < codes.length(); i++) {
349#ifdef DEBUG
350 if (codes[i] == topmost_optimized_code) {
351 DCHECK(safe_to_deopt_topmost_optimized_code);
352 }
353#endif
354 // It is finally time to die, code object.
355
356 // Remove the code from optimized code map.
357 DeoptimizationInputData* deopt_data =
358 DeoptimizationInputData::cast(codes[i]->deoptimization_data());
359 SharedFunctionInfo* shared =
360 SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
361 shared->EvictFromOptimizedCodeMap(codes[i], "deoptimized code");
362
363 // Do platform-specific patching to force any activations to lazy deopt.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 PatchCodeForDeoptimization(isolate, codes[i]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 // We might be in the middle of incremental marking with compaction.
367 // Tell collector to treat this code object in a special way and
368 // ignore all slots that might have been recorded on it.
369 isolate->heap()->mark_compact_collector()->InvalidateCode(codes[i]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370 }
371}
372
373
374void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100375 TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
376 TRACE_EVENT0("v8", "V8.DeoptimizeCode");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000377 if (FLAG_trace_deopt) {
378 CodeTracer::Scope scope(isolate->GetCodeTracer());
379 PrintF(scope.file(), "[deoptimize all code in all contexts]\n");
380 }
381 DisallowHeapAllocation no_allocation;
382 // For all contexts, mark all code, then deoptimize.
383 Object* context = isolate->heap()->native_contexts_list();
384 while (!context->IsUndefined()) {
385 Context* native_context = Context::cast(context);
386 MarkAllCodeForContext(native_context);
387 DeoptimizeMarkedCodeForContext(native_context);
388 context = native_context->get(Context::NEXT_CONTEXT_LINK);
389 }
390}
391
392
393void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100394 TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
395 TRACE_EVENT0("v8", "V8.DeoptimizeCode");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000396 if (FLAG_trace_deopt) {
397 CodeTracer::Scope scope(isolate->GetCodeTracer());
398 PrintF(scope.file(), "[deoptimize marked code in all contexts]\n");
399 }
400 DisallowHeapAllocation no_allocation;
401 // For all contexts, deoptimize code already marked.
402 Object* context = isolate->heap()->native_contexts_list();
403 while (!context->IsUndefined()) {
404 Context* native_context = Context::cast(context);
405 DeoptimizeMarkedCodeForContext(native_context);
406 context = native_context->get(Context::NEXT_CONTEXT_LINK);
407 }
408}
409
410
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000411void Deoptimizer::MarkAllCodeForContext(Context* context) {
412 Object* element = context->OptimizedCodeListHead();
413 while (!element->IsUndefined()) {
414 Code* code = Code::cast(element);
415 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
416 code->set_marked_for_deoptimization(true);
417 element = code->next_code_link();
418 }
419}
420
421
422void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100423 TimerEventScope<TimerEventDeoptimizeCode> timer(function->GetIsolate());
424 TRACE_EVENT0("v8", "V8.DeoptimizeCode");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425 Code* code = function->code();
426 if (code->kind() == Code::OPTIMIZED_FUNCTION) {
427 // Mark the code for deoptimization and unlink any functions that also
428 // refer to that code. The code cannot be shared across native contexts,
429 // so we only need to search one.
430 code->set_marked_for_deoptimization(true);
431 DeoptimizeMarkedCodeForContext(function->context()->native_context());
432 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100433}
434
435
Ben Murdoch8b112d22011-06-08 16:22:53 +0100436void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100437 deoptimizer->DoComputeOutputFrames();
438}
439
440
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441bool Deoptimizer::TraceEnabledFor(BailoutType deopt_type,
442 StackFrame::Type frame_type) {
443 switch (deopt_type) {
444 case EAGER:
445 case SOFT:
446 case LAZY:
447 case DEBUGGER:
448 return (frame_type == StackFrame::STUB)
449 ? FLAG_trace_stub_failures
450 : FLAG_trace_deopt;
451 }
452 FATAL("Unsupported deopt type");
453 return false;
454}
455
456
457const char* Deoptimizer::MessageFor(BailoutType type) {
458 switch (type) {
459 case EAGER: return "eager";
460 case SOFT: return "soft";
461 case LAZY: return "lazy";
462 case DEBUGGER: return "debugger";
463 }
464 FATAL("Unsupported deopt type");
465 return NULL;
466}
467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
469 BailoutType type, unsigned bailout_id, Address from,
470 int fp_to_sp_delta, Code* optimized_code)
Steve Block44f0eee2011-05-26 01:26:41 +0100471 : isolate_(isolate),
472 function_(function),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100473 bailout_id_(bailout_id),
474 bailout_type_(type),
475 from_(from),
476 fp_to_sp_delta_(fp_to_sp_delta),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477 has_alignment_padding_(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100478 deoptimizing_throw_(false),
479 catch_handler_data_(-1),
480 catch_handler_pc_offset_(-1),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 input_(nullptr),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100482 output_count_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100483 jsframe_count_(0),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 output_(nullptr),
485 trace_scope_(nullptr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100486 if (isolate->deoptimizer_lazy_throw()) {
487 isolate->set_deoptimizer_lazy_throw(false);
488 deoptimizing_throw_ = true;
489 }
490
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491 // For COMPILED_STUBs called from builtins, the function pointer is a SMI
492 // indicating an internal frame.
493 if (function->IsSmi()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 function = nullptr;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100495 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 DCHECK(from != nullptr);
497 if (function != nullptr && function->IsOptimized()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 function->shared()->increment_deopt_count();
499 if (bailout_type_ == Deoptimizer::SOFT) {
500 isolate->counters()->soft_deopts_executed()->Increment();
501 // Soft deopts shouldn't count against the overall re-optimization count
502 // that can eventually lead to disabling optimization for a function.
503 int opt_count = function->shared()->opt_count();
504 if (opt_count > 0) opt_count--;
505 function->shared()->set_opt_count(opt_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100506 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100507 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000508 compiled_code_ = FindOptimizedCode(function, optimized_code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509#if DEBUG
510 DCHECK(compiled_code_ != NULL);
511 if (type == EAGER || type == SOFT || type == LAZY) {
512 DCHECK(compiled_code_->kind() != Code::FUNCTION);
513 }
514#endif
515
516 StackFrame::Type frame_type = function == NULL
517 ? StackFrame::STUB
518 : StackFrame::JAVA_SCRIPT;
519 trace_scope_ = TraceEnabledFor(type, frame_type) ?
520 new CodeTracer::Scope(isolate->GetCodeTracer()) : NULL;
521#ifdef DEBUG
522 CHECK(AllowHeapAllocation::IsAllowed());
523 disallow_heap_allocation_ = new DisallowHeapAllocation();
524#endif // DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
526 PROFILE(isolate_, CodeDeoptEvent(compiled_code_, from_, fp_to_sp_delta_));
527 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100528 unsigned size = ComputeInputFrameSize();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100529 int parameter_count =
530 function == nullptr
531 ? 0
532 : (function->shared()->internal_formal_parameter_count() + 1);
533 input_ = new (size) FrameDescription(size, parameter_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 input_->SetFrameType(frame_type);
535}
536
537
538Code* Deoptimizer::FindOptimizedCode(JSFunction* function,
539 Code* optimized_code) {
540 switch (bailout_type_) {
541 case Deoptimizer::SOFT:
542 case Deoptimizer::EAGER:
543 case Deoptimizer::LAZY: {
544 Code* compiled_code = FindDeoptimizingCode(from_);
545 return (compiled_code == NULL)
546 ? static_cast<Code*>(isolate_->FindCodeObject(from_))
547 : compiled_code;
548 }
549 case Deoptimizer::DEBUGGER:
550 DCHECK(optimized_code->contains(from_));
551 return optimized_code;
552 }
553 FATAL("Could not find code for optimized function");
554 return NULL;
555}
556
557
558void Deoptimizer::PrintFunctionName() {
559 if (function_->IsJSFunction()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400560 function_->ShortPrint(trace_scope_->file());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 } else {
562 PrintF(trace_scope_->file(),
563 "%s", Code::Kind2String(compiled_code_->kind()));
564 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100565}
566
567
568Deoptimizer::~Deoptimizer() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 DCHECK(input_ == NULL && output_ == NULL);
570 DCHECK(disallow_heap_allocation_ == NULL);
571 delete trace_scope_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100572}
573
574
575void Deoptimizer::DeleteFrameDescriptions() {
576 delete input_;
577 for (int i = 0; i < output_count_; ++i) {
578 if (output_[i] != input_) delete output_[i];
579 }
580 delete[] output_;
581 input_ = NULL;
582 output_ = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583#ifdef DEBUG
584 CHECK(!AllowHeapAllocation::IsAllowed());
585 CHECK(disallow_heap_allocation_ != NULL);
586 delete disallow_heap_allocation_;
587 disallow_heap_allocation_ = NULL;
588#endif // DEBUG
Ben Murdochb0fe1622011-05-05 13:52:32 +0100589}
590
591
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
593 int id,
594 BailoutType type,
595 GetEntryMode mode) {
596 CHECK_GE(id, 0);
597 if (id >= kMaxNumberOfEntries) return NULL;
598 if (mode == ENSURE_ENTRY_CODE) {
599 EnsureCodeForDeoptimizationEntry(isolate, type, id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100600 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 CHECK_EQ(mode, CALCULATE_ENTRY_ADDRESS);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100602 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000603 DeoptimizerData* data = isolate->deoptimizer_data();
604 CHECK_LT(type, kBailoutTypesWithCodeEntry);
605 MemoryChunk* base = data->deopt_entry_code_[type];
606 return base->area_start() + (id * table_entry_size_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100607}
608
609
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000610int Deoptimizer::GetDeoptimizationId(Isolate* isolate,
611 Address addr,
612 BailoutType type) {
613 DeoptimizerData* data = isolate->deoptimizer_data();
614 MemoryChunk* base = data->deopt_entry_code_[type];
615 Address start = base->area_start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400616 if (addr < start ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000617 addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100618 return kNotDeoptimizationEntry;
619 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620 DCHECK_EQ(0,
621 static_cast<int>(addr - start) % table_entry_size_);
622 return static_cast<int>(addr - start) / table_entry_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100623}
624
625
Steve Block9fac8402011-05-12 15:51:54 +0100626int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000627 BailoutId id,
Steve Block9fac8402011-05-12 15:51:54 +0100628 SharedFunctionInfo* shared) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100629 // TODO(kasperl): For now, we do a simple linear search for the PC
630 // offset associated with the given node id. This should probably be
631 // changed to a binary search.
632 int length = data->DeoptPoints();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100633 for (int i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 if (data->AstId(i) == id) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100635 return data->PcAndState(i)->value();
636 }
637 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000638 OFStream os(stderr);
639 os << "[couldn't find pc offset for node=" << id.ToInt() << "]\n"
640 << "[method: " << shared->DebugName()->ToCString().get() << "]\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400641 << "[source:\n" << SourceCodeOf(shared) << "\n]" << std::endl;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100642
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 shared->GetHeap()->isolate()->PushStackTraceAndDie(0xfefefefe, data, shared,
644 0xfefefeff);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000645 FATAL("unable to find pc offset during deoptimization");
Ben Murdochb0fe1622011-05-05 13:52:32 +0100646 return -1;
647}
648
649
Steve Block44f0eee2011-05-26 01:26:41 +0100650int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100651 int length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 // Count all entries in the deoptimizing code list of every context.
653 Object* context = isolate->heap()->native_contexts_list();
654 while (!context->IsUndefined()) {
655 Context* native_context = Context::cast(context);
656 Object* element = native_context->DeoptimizedCodeListHead();
657 while (!element->IsUndefined()) {
658 Code* code = Code::cast(element);
659 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
660 length++;
661 element = code->next_code_link();
662 }
663 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100664 }
665 return length;
666}
667
Ben Murdoch097c5b22016-05-18 11:27:45 +0100668namespace {
669
670int LookupCatchHandler(TranslatedFrame* translated_frame, int* data_out) {
671 switch (translated_frame->kind()) {
672 case TranslatedFrame::kFunction: {
673 BailoutId node_id = translated_frame->node_id();
674 JSFunction* function =
675 JSFunction::cast(translated_frame->begin()->GetRawValue());
676 Code* non_optimized_code = function->shared()->code();
677 FixedArray* raw_data = non_optimized_code->deoptimization_data();
678 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
679 unsigned pc_and_state =
680 Deoptimizer::GetOutputInfo(data, node_id, function->shared());
681 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
682 HandlerTable* table =
683 HandlerTable::cast(non_optimized_code->handler_table());
684 HandlerTable::CatchPrediction prediction;
685 return table->LookupRange(pc_offset, data_out, &prediction);
686 }
687 case TranslatedFrame::kInterpretedFunction: {
688 int bytecode_offset = translated_frame->node_id().ToInt();
689 JSFunction* function =
690 JSFunction::cast(translated_frame->begin()->GetRawValue());
691 BytecodeArray* bytecode = function->shared()->bytecode_array();
692 HandlerTable* table = HandlerTable::cast(bytecode->handler_table());
693 HandlerTable::CatchPrediction prediction;
694 return table->LookupRange(bytecode_offset, data_out, &prediction);
695 }
696 default:
697 break;
698 }
699 return -1;
700}
701
702} // namespace
Ben Murdochb0fe1622011-05-05 13:52:32 +0100703
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100704// We rely on this function not causing a GC. It is called from generated code
705// without having a real stack frame in place.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100706void Deoptimizer::DoComputeOutputFrames() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 base::ElapsedTimer timer;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100708
709 // Determine basic deoptimization information. The optimized frame is
710 // described by the input data.
711 DeoptimizationInputData* input_data =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
713
714 if (trace_scope_ != NULL) {
715 timer.Start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400716 PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ",
717 MessageFor(bailout_type_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 PrintFunctionName();
719 PrintF(trace_scope_->file(),
720 " (opt #%d) @%d, FP to SP delta: %d]\n",
721 input_data->OptimizationId()->value(),
722 bailout_id_,
723 fp_to_sp_delta_);
724 if (bailout_type_ == EAGER || bailout_type_ == SOFT ||
725 (compiled_code_->is_hydrogen_stub())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000726 compiled_code_->PrintDeoptLocation(trace_scope_->file(), from_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000727 }
728 }
729
730 BailoutId node_id = input_data->AstId(bailout_id_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100731 ByteArray* translations = input_data->TranslationByteArray();
732 unsigned translation_index =
733 input_data->TranslationIndex(bailout_id_)->value();
734
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 TranslationIterator state_iterator(translations, translation_index);
736 translated_state_.Init(
737 input_->GetFramePointerAddress(), &state_iterator,
738 input_data->LiteralArray(), input_->GetRegisterValues(),
739 trace_scope_ == nullptr ? nullptr : trace_scope_->file());
740
Ben Murdochb0fe1622011-05-05 13:52:32 +0100741 // Do the input frame to output frame(s) translation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000742 size_t count = translated_state_.frames().size();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100743 // If we are supposed to go to the catch handler, find the catching frame
744 // for the catch and make sure we only deoptimize upto that frame.
745 if (deoptimizing_throw_) {
746 size_t catch_handler_frame_index = count;
747 for (size_t i = count; i-- > 0;) {
748 catch_handler_pc_offset_ = LookupCatchHandler(
749 &(translated_state_.frames()[i]), &catch_handler_data_);
750 if (catch_handler_pc_offset_ >= 0) {
751 catch_handler_frame_index = i;
752 break;
753 }
754 }
755 CHECK_LT(catch_handler_frame_index, count);
756 count = catch_handler_frame_index + 1;
757 }
758
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759 DCHECK(output_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100760 output_ = new FrameDescription*[count];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 for (size_t i = 0; i < count; ++i) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100762 output_[i] = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100763 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000764 output_count_ = static_cast<int>(count);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100765
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000766 Register fp_reg = JavaScriptFrame::fp_register();
767 stack_fp_ = reinterpret_cast<Address>(
768 input_->GetRegister(fp_reg.code()) +
769 has_alignment_padding_ * kPointerSize);
770
Ben Murdochb0fe1622011-05-05 13:52:32 +0100771 // Translate each output frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000772 for (size_t i = 0; i < count; ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100773 // Read the ast node id, function, and frame height for this output frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000774 int frame_index = static_cast<int>(i);
775 switch (translated_state_.frames()[i].kind()) {
776 case TranslatedFrame::kFunction:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100777 DoComputeJSFrame(frame_index, deoptimizing_throw_ && i == count - 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100778 jsframe_count_++;
779 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000780 case TranslatedFrame::kInterpretedFunction:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100781 DoComputeInterpretedFrame(frame_index,
782 deoptimizing_throw_ && i == count - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000783 jsframe_count_++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100784 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785 case TranslatedFrame::kArgumentsAdaptor:
786 DoComputeArgumentsAdaptorFrame(frame_index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100787 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 case TranslatedFrame::kConstructStub:
789 DoComputeConstructStubFrame(frame_index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000790 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000791 case TranslatedFrame::kGetter:
792 DoComputeAccessorStubFrame(frame_index, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000793 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000794 case TranslatedFrame::kSetter:
795 DoComputeAccessorStubFrame(frame_index, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000796 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 case TranslatedFrame::kCompiledStub:
798 DoComputeCompiledStubFrame(frame_index);
799 break;
800 case TranslatedFrame::kInvalid:
801 FATAL("invalid frame");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100802 break;
803 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100804 }
805
806 // Print some helpful diagnostic information.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000807 if (trace_scope_ != NULL) {
808 double ms = timer.Elapsed().InMillisecondsF();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100809 int index = output_count_ - 1; // Index of the topmost frame.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400810 PrintF(trace_scope_->file(), "[deoptimizing (%s): end ",
811 MessageFor(bailout_type_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000812 PrintFunctionName();
813 PrintF(trace_scope_->file(),
814 " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
815 " took %0.3f ms]\n",
816 bailout_id_,
817 node_id.ToInt(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100818 output_[index]->GetPc(),
819 FullCodeGenerator::State2String(
820 static_cast<FullCodeGenerator::State>(
821 output_[index]->GetState()->value())),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000822 has_alignment_padding_ ? "with padding" : "no padding",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100823 ms);
824 }
825}
826
Ben Murdoch097c5b22016-05-18 11:27:45 +0100827void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000828 TranslatedFrame* translated_frame =
829 &(translated_state_.frames()[frame_index]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100830 SharedFunctionInfo* shared = translated_frame->raw_shared_info();
831
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832 TranslatedFrame::iterator value_iterator = translated_frame->begin();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100833 bool is_bottommost = (0 == frame_index);
834 bool is_topmost = (output_count_ - 1 == frame_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 int input_index = 0;
836
837 BailoutId node_id = translated_frame->node_id();
838 unsigned height =
839 translated_frame->height() - 1; // Do not count the context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000840 unsigned height_in_bytes = height * kPointerSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100841 if (goto_catch_handler) {
842 // Take the stack height from the handler table.
843 height = catch_handler_data_;
844 // We also make space for the exception itself.
845 height_in_bytes = (height + 1) * kPointerSize;
846 CHECK(is_topmost);
847 }
848
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000849 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
850 value_iterator++;
851 input_index++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000852 if (trace_scope_ != NULL) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000853 PrintF(trace_scope_->file(), " translating frame ");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100854 base::SmartArrayPointer<char> name = shared->DebugName()->ToCString();
855 PrintF(trace_scope_->file(), "%s", name.get());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000856 PrintF(trace_scope_->file(),
857 " => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100858 PrintF(trace_scope_->file(), " => node=%d, height=%d%s\n", node_id.ToInt(),
859 height_in_bytes, goto_catch_handler ? " (throw)" : "");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000860 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100861
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000862 // The 'fixed' part of the frame consists of the incoming parameters and
863 // the part described by JavaScriptFrameConstants.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100864 unsigned fixed_frame_size = ComputeJavascriptFixedSize(shared);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000865 unsigned input_frame_size = input_->GetFrameSize();
866 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
867
868 // Allocate and store the output frame description.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100869 int parameter_count = shared->internal_formal_parameter_count() + 1;
870 FrameDescription* output_frame = new (output_frame_size)
871 FrameDescription(output_frame_size, parameter_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000872 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
873
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000874 CHECK(frame_index >= 0 && frame_index < output_count_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000875 CHECK_NULL(output_[frame_index]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000876 output_[frame_index] = output_frame;
877
878 // The top address for the bottommost output frame can be computed from
879 // the input frame pointer and the output frame's height. For all
880 // subsequent output frames, it can be computed from the previous one's
881 // top address and the current frame's size.
882 Register fp_reg = JavaScriptFrame::fp_register();
883 intptr_t top_address;
884 if (is_bottommost) {
885 // Determine whether the input frame contains alignment padding.
886 has_alignment_padding_ =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100887 (!compiled_code_->is_turbofanned() && HasAlignmentPadding(shared)) ? 1
888 : 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000889 // 2 = context and function in the frame.
890 // If the optimized frame had alignment padding, adjust the frame pointer
891 // to point to the new position of the old frame pointer after padding
892 // is removed. Subtract 2 * kPointerSize for the context and function slots.
893 top_address = input_->GetRegister(fp_reg.code()) -
894 StandardFrameConstants::kFixedFrameSizeFromFp -
895 height_in_bytes + has_alignment_padding_ * kPointerSize;
896 } else {
897 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
898 }
899 output_frame->SetTop(top_address);
900
901 // Compute the incoming parameter translation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000902 unsigned output_offset = output_frame_size;
903 unsigned input_offset = input_frame_size;
904 for (int i = 0; i < parameter_count; ++i) {
905 output_offset -= kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000906 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
907 output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 }
909 input_offset -= (parameter_count * kPointerSize);
910
911 // There are no translation commands for the caller's pc and fp, the
912 // context, and the function. Synthesize their values and set them up
913 // explicitly.
914 //
915 // The caller's pc for the bottommost output frame is the same as in the
916 // input frame. For all subsequent output frames, it can be read from the
917 // previous one. This frame's pc can be computed from the non-optimized
918 // function code and AST id of the bailout.
919 output_offset -= kPCOnStackSize;
920 input_offset -= kPCOnStackSize;
921 intptr_t value;
922 if (is_bottommost) {
923 value = input_->GetFrameSlot(input_offset);
924 } else {
925 value = output_[frame_index - 1]->GetPc();
926 }
927 output_frame->SetCallerPc(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000928 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000929
930 // The caller's frame pointer for the bottommost output frame is the same
931 // as in the input frame. For all subsequent output frames, it can be
932 // read from the previous one. Also compute and set this frame's frame
933 // pointer.
934 output_offset -= kFPOnStackSize;
935 input_offset -= kFPOnStackSize;
936 if (is_bottommost) {
937 value = input_->GetFrameSlot(input_offset);
938 } else {
939 value = output_[frame_index - 1]->GetFp();
940 }
941 output_frame->SetCallerFp(output_offset, value);
942 intptr_t fp_value = top_address + output_offset;
943 DCHECK(!is_bottommost || (input_->GetRegister(fp_reg.code()) +
944 has_alignment_padding_ * kPointerSize) == fp_value);
945 output_frame->SetFp(fp_value);
946 if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000948 DCHECK(!is_bottommost || !has_alignment_padding_ ||
949 (fp_value & kPointerSize) != 0);
950
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000951 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000952 // For the bottommost output frame the constant pool pointer can be gotten
953 // from the input frame. For subsequent output frames, it can be read from
954 // the previous frame.
955 output_offset -= kPointerSize;
956 input_offset -= kPointerSize;
957 if (is_bottommost) {
958 value = input_->GetFrameSlot(input_offset);
959 } else {
960 value = output_[frame_index - 1]->GetConstantPool();
961 }
962 output_frame->SetCallerConstantPool(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000963 DebugPrintOutputSlot(value, frame_index, output_offset,
964 "caller's constant_pool\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000965 }
966
967 // For the bottommost output frame the context can be gotten from the input
968 // frame. For all subsequent output frames it can be gotten from the function
969 // so long as we don't inline functions that need local contexts.
970 Register context_reg = JavaScriptFrame::context_register();
971 output_offset -= kPointerSize;
972 input_offset -= kPointerSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100973
974 TranslatedFrame::iterator context_pos = value_iterator;
975 int context_input_index = input_index;
976 // When deoptimizing into a catch block, we need to take the context
977 // from just above the top of the operand stack (we push the context
978 // at the entry of the try block).
979 if (goto_catch_handler) {
980 for (unsigned i = 0; i < height + 1; ++i) {
981 context_pos++;
982 context_input_index++;
983 }
984 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000985 // Read the context from the translations.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100986 Object* context = context_pos->GetRawValue();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000987 if (context == isolate_->heap()->undefined_value()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000988 // If the context was optimized away, just use the context from
989 // the activation. This should only apply to Crankshaft code.
990 CHECK(!compiled_code_->is_turbofanned());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000991 context =
992 is_bottommost
993 ? reinterpret_cast<Object*>(input_->GetFrameSlot(input_offset))
994 : function->context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000995 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000996 value = reinterpret_cast<intptr_t>(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000997 output_frame->SetContext(value);
998 if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100999 WriteValueToOutput(context, context_input_index, frame_index, output_offset,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001000 "context ");
1001 if (context == isolate_->heap()->arguments_marker()) {
1002 Address output_address =
1003 reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
1004 output_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001005 values_to_materialize_.push_back({output_address, context_pos});
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001006 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001007 value_iterator++;
1008 input_index++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009
1010 // The function was mentioned explicitly in the BEGIN_FRAME.
1011 output_offset -= kPointerSize;
1012 input_offset -= kPointerSize;
1013 value = reinterpret_cast<intptr_t>(function);
1014 // The function for the bottommost output frame should also agree with the
1015 // input frame.
1016 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017 WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001018
1019 // Translate the rest of the frame.
1020 for (unsigned i = 0; i < height; ++i) {
1021 output_offset -= kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1023 output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001024 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001025 if (goto_catch_handler) {
1026 // Write out the exception for the catch handler.
1027 output_offset -= kPointerSize;
1028 Object* exception_obj = reinterpret_cast<Object*>(
1029 input_->GetRegister(FullCodeGenerator::result_register().code()));
1030 WriteValueToOutput(exception_obj, input_index, frame_index, output_offset,
1031 "exception ");
1032 input_index++;
1033 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001034 CHECK_EQ(0u, output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001035
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 // Update constant pool.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001037 Code* non_optimized_code = shared->code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001038 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001039 intptr_t constant_pool_value =
1040 reinterpret_cast<intptr_t>(non_optimized_code->constant_pool());
1041 output_frame->SetConstantPool(constant_pool_value);
1042 if (is_topmost) {
1043 Register constant_pool_reg =
1044 JavaScriptFrame::constant_pool_pointer_register();
1045 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1046 }
1047 }
1048
Ben Murdoch097c5b22016-05-18 11:27:45 +01001049 // Compute this frame's PC, state, and continuation.
1050 FixedArray* raw_data = non_optimized_code->deoptimization_data();
1051 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
1052 Address start = non_optimized_code->instruction_start();
1053 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
1054 unsigned pc_offset = goto_catch_handler
1055 ? catch_handler_pc_offset_
1056 : FullCodeGenerator::PcField::decode(pc_and_state);
1057 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
1058 output_frame->SetPc(pc_value);
1059
1060 // If we are going to the catch handler, then the exception lives in
1061 // the accumulator.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001062 FullCodeGenerator::State state =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001063 goto_catch_handler ? FullCodeGenerator::TOS_REG
1064 : FullCodeGenerator::StateField::decode(pc_and_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001065 output_frame->SetState(Smi::FromInt(state));
1066
1067 // Set the continuation for the topmost frame.
1068 if (is_topmost && bailout_type_ != DEBUGGER) {
1069 Builtins* builtins = isolate_->builtins();
1070 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
1071 if (bailout_type_ == LAZY) {
1072 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
1073 } else if (bailout_type_ == SOFT) {
1074 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
1075 } else {
1076 CHECK_EQ(bailout_type_, EAGER);
1077 }
1078 output_frame->SetContinuation(
1079 reinterpret_cast<intptr_t>(continuation->entry()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001080 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001081}
1082
Ben Murdoch097c5b22016-05-18 11:27:45 +01001083void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
1084 bool goto_catch_handler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001085 TranslatedFrame* translated_frame =
1086 &(translated_state_.frames()[frame_index]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001087 SharedFunctionInfo* shared = translated_frame->raw_shared_info();
1088
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001089 TranslatedFrame::iterator value_iterator = translated_frame->begin();
1090 int input_index = 0;
1091
Ben Murdoch097c5b22016-05-18 11:27:45 +01001092 int bytecode_offset = translated_frame->node_id().ToInt();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001093 unsigned height = translated_frame->height();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001094 unsigned height_in_bytes = height * kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
1096 value_iterator++;
1097 input_index++;
1098 if (trace_scope_ != NULL) {
1099 PrintF(trace_scope_->file(), " translating interpreted frame ");
Ben Murdoch097c5b22016-05-18 11:27:45 +01001100 base::SmartArrayPointer<char> name = shared->DebugName()->ToCString();
1101 PrintF(trace_scope_->file(), "%s", name.get());
1102 PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d%s\n",
1103 bytecode_offset, height_in_bytes,
1104 goto_catch_handler ? " (throw)" : "");
1105 }
1106 if (goto_catch_handler) {
1107 bytecode_offset = catch_handler_pc_offset_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001108 }
1109
1110 // The 'fixed' part of the frame consists of the incoming parameters and
1111 // the part described by InterpreterFrameConstants.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001112 unsigned fixed_frame_size = ComputeInterpretedFixedSize(shared);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001113 unsigned input_frame_size = input_->GetFrameSize();
1114 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1115
1116 // Allocate and store the output frame description.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001117 int parameter_count = shared->internal_formal_parameter_count() + 1;
1118 FrameDescription* output_frame = new (output_frame_size)
1119 FrameDescription(output_frame_size, parameter_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001120 output_frame->SetFrameType(StackFrame::INTERPRETED);
1121
1122 bool is_bottommost = (0 == frame_index);
1123 bool is_topmost = (output_count_ - 1 == frame_index);
1124 CHECK(frame_index >= 0 && frame_index < output_count_);
1125 CHECK_NULL(output_[frame_index]);
1126 output_[frame_index] = output_frame;
1127
1128 // The top address for the bottommost output frame can be computed from
1129 // the input frame pointer and the output frame's height. For all
1130 // subsequent output frames, it can be computed from the previous one's
1131 // top address and the current frame's size.
1132 Register fp_reg = InterpretedFrame::fp_register();
1133 intptr_t top_address;
1134 if (is_bottommost) {
1135 // Subtract interpreter fixed frame size for the context function slots,
1136 // new,target and bytecode offset.
1137 top_address = input_->GetRegister(fp_reg.code()) -
1138 InterpreterFrameConstants::kFixedFrameSizeFromFp -
1139 height_in_bytes;
1140 } else {
1141 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1142 }
1143 output_frame->SetTop(top_address);
1144
1145 // Compute the incoming parameter translation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146 unsigned output_offset = output_frame_size;
1147 unsigned input_offset = input_frame_size;
1148 for (int i = 0; i < parameter_count; ++i) {
1149 output_offset -= kPointerSize;
1150 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1151 output_offset);
1152 }
1153 input_offset -= (parameter_count * kPointerSize);
1154
1155 // There are no translation commands for the caller's pc and fp, the
1156 // context, the function, new.target and the bytecode offset. Synthesize
1157 // their values and set them up
1158 // explicitly.
1159 //
1160 // The caller's pc for the bottommost output frame is the same as in the
1161 // input frame. For all subsequent output frames, it can be read from the
1162 // previous one. This frame's pc can be computed from the non-optimized
1163 // function code and AST id of the bailout.
1164 output_offset -= kPCOnStackSize;
1165 input_offset -= kPCOnStackSize;
1166 intptr_t value;
1167 if (is_bottommost) {
1168 value = input_->GetFrameSlot(input_offset);
1169 } else {
1170 value = output_[frame_index - 1]->GetPc();
1171 }
1172 output_frame->SetCallerPc(output_offset, value);
1173 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n");
1174
1175 // The caller's frame pointer for the bottommost output frame is the same
1176 // as in the input frame. For all subsequent output frames, it can be
1177 // read from the previous one. Also compute and set this frame's frame
1178 // pointer.
1179 output_offset -= kFPOnStackSize;
1180 input_offset -= kFPOnStackSize;
1181 if (is_bottommost) {
1182 value = input_->GetFrameSlot(input_offset);
1183 } else {
1184 value = output_[frame_index - 1]->GetFp();
1185 }
1186 output_frame->SetCallerFp(output_offset, value);
1187 intptr_t fp_value = top_address + output_offset;
1188 DCHECK(!is_bottommost ||
1189 (input_->GetRegister(fp_reg.code()) +
1190 has_alignment_padding_ * kPointerSize) == fp_value);
1191 output_frame->SetFp(fp_value);
1192 if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
1193 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
1194 DCHECK(!is_bottommost || !has_alignment_padding_ ||
1195 (fp_value & kPointerSize) != 0);
1196
1197 if (FLAG_enable_embedded_constant_pool) {
1198 // For the bottommost output frame the constant pool pointer can be gotten
1199 // from the input frame. For subsequent output frames, it can be read from
1200 // the previous frame.
1201 output_offset -= kPointerSize;
1202 input_offset -= kPointerSize;
1203 if (is_bottommost) {
1204 value = input_->GetFrameSlot(input_offset);
1205 } else {
1206 value = output_[frame_index - 1]->GetConstantPool();
1207 }
1208 output_frame->SetCallerConstantPool(output_offset, value);
1209 DebugPrintOutputSlot(value, frame_index, output_offset,
1210 "caller's constant_pool\n");
1211 }
1212
1213 // For the bottommost output frame the context can be gotten from the input
1214 // frame. For all subsequent output frames it can be gotten from the function
1215 // so long as we don't inline functions that need local contexts.
1216 Register context_reg = InterpretedFrame::context_register();
1217 output_offset -= kPointerSize;
1218 input_offset -= kPointerSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001219
1220 // When deoptimizing into a catch block, we need to take the context
1221 // from a register that was specified in the handler table.
1222 TranslatedFrame::iterator context_pos = value_iterator;
1223 int context_input_index = input_index;
1224 if (goto_catch_handler) {
1225 // Skip to the translated value of the register specified
1226 // in the handler table.
1227 for (int i = 0; i < catch_handler_data_ + 1; ++i) {
1228 context_pos++;
1229 context_input_index++;
1230 }
1231 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 // Read the context from the translations.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001233 Object* context = context_pos->GetRawValue();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234 // The context should not be a placeholder for a materialized object.
1235 CHECK(context != isolate_->heap()->arguments_marker());
1236 value = reinterpret_cast<intptr_t>(context);
1237 output_frame->SetContext(value);
1238 if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001239 WriteValueToOutput(context, context_input_index, frame_index, output_offset,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240 "context ");
1241 value_iterator++;
1242 input_index++;
1243
1244 // The function was mentioned explicitly in the BEGIN_FRAME.
1245 output_offset -= kPointerSize;
1246 input_offset -= kPointerSize;
1247 value = reinterpret_cast<intptr_t>(function);
1248 // The function for the bottommost output frame should also agree with the
1249 // input frame.
1250 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
1251 WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
1252
Ben Murdoch097c5b22016-05-18 11:27:45 +01001253 // The new.target slot is only used during function activiation which is
1254 // before the first deopt point, so should never be needed. Just set it to
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001255 // undefined.
1256 output_offset -= kPointerSize;
1257 input_offset -= kPointerSize;
1258 Object* new_target = isolate_->heap()->undefined_value();
1259 WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target ");
1260
Ben Murdoch097c5b22016-05-18 11:27:45 +01001261 // Set the bytecode array pointer.
1262 output_offset -= kPointerSize;
1263 input_offset -= kPointerSize;
1264 Object* bytecode_array = shared->bytecode_array();
1265 WriteValueToOutput(bytecode_array, 0, frame_index, output_offset,
1266 "bytecode array ");
1267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268 // The bytecode offset was mentioned explicitly in the BEGIN_FRAME.
1269 output_offset -= kPointerSize;
1270 input_offset -= kPointerSize;
1271 int raw_bytecode_offset =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001272 BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset);
1274 WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset,
1275 "bytecode offset ");
1276
1277 // Translate the rest of the interpreter registers in the frame.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001278 for (unsigned i = 0; i < height - 1; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001279 output_offset -= kPointerSize;
1280 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1281 output_offset);
1282 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001283
1284 // Put the accumulator on the stack. It will be popped by the
1285 // InterpreterNotifyDeopt builtin (possibly after materialization).
1286 output_offset -= kPointerSize;
1287 if (goto_catch_handler) {
1288 // If we are lazy deopting to a catch handler, we set the accumulator to
1289 // the exception (which lives in the result register).
1290 intptr_t accumulator_value =
1291 input_->GetRegister(FullCodeGenerator::result_register().code());
1292 WriteValueToOutput(reinterpret_cast<Object*>(accumulator_value), 0,
1293 frame_index, output_offset, "accumulator ");
1294 value_iterator++;
1295 } else {
1296 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1297 output_offset);
1298 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001299 CHECK_EQ(0u, output_offset);
1300
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001301 Builtins* builtins = isolate_->builtins();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001302 Code* dispatch_builtin =
1303 builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch);
1304 output_frame->SetPc(reinterpret_cast<intptr_t>(dispatch_builtin->entry()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305 output_frame->SetState(0);
1306
1307 // Update constant pool.
1308 if (FLAG_enable_embedded_constant_pool) {
1309 intptr_t constant_pool_value =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001310 reinterpret_cast<intptr_t>(dispatch_builtin->constant_pool());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001311 output_frame->SetConstantPool(constant_pool_value);
1312 if (is_topmost) {
1313 Register constant_pool_reg =
1314 InterpretedFrame::constant_pool_pointer_register();
1315 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1316 }
1317 }
1318
1319 // Set the continuation for the topmost frame.
1320 if (is_topmost && bailout_type_ != DEBUGGER) {
1321 Code* continuation =
1322 builtins->builtin(Builtins::kInterpreterNotifyDeoptimized);
1323 if (bailout_type_ == LAZY) {
1324 continuation =
1325 builtins->builtin(Builtins::kInterpreterNotifyLazyDeoptimized);
1326 } else if (bailout_type_ == SOFT) {
1327 continuation =
1328 builtins->builtin(Builtins::kInterpreterNotifySoftDeoptimized);
1329 } else {
1330 CHECK_EQ(bailout_type_, EAGER);
1331 }
1332 output_frame->SetContinuation(
1333 reinterpret_cast<intptr_t>(continuation->entry()));
1334 }
1335}
1336
1337
1338void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) {
1339 TranslatedFrame* translated_frame =
1340 &(translated_state_.frames()[frame_index]);
1341 TranslatedFrame::iterator value_iterator = translated_frame->begin();
1342 int input_index = 0;
1343
1344 unsigned height = translated_frame->height();
1345 unsigned height_in_bytes = height * kPointerSize;
1346 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
1347 value_iterator++;
1348 input_index++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 if (trace_scope_ != NULL) {
1350 PrintF(trace_scope_->file(),
1351 " translating arguments adaptor => height=%d\n", height_in_bytes);
1352 }
1353
1354 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
1355 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1356
1357 // Allocate and store the output frame description.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001358 int parameter_count = height;
1359 FrameDescription* output_frame = new (output_frame_size)
1360 FrameDescription(output_frame_size, parameter_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
1362
1363 // Arguments adaptor can not be topmost or bottommost.
1364 CHECK(frame_index > 0 && frame_index < output_count_ - 1);
1365 CHECK(output_[frame_index] == NULL);
1366 output_[frame_index] = output_frame;
1367
1368 // The top address of the frame is computed from the previous
1369 // frame's top and this frame's size.
1370 intptr_t top_address;
1371 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1372 output_frame->SetTop(top_address);
1373
1374 // Compute the incoming parameter translation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001375 unsigned output_offset = output_frame_size;
1376 for (int i = 0; i < parameter_count; ++i) {
1377 output_offset -= kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1379 output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001380 }
1381
1382 // Read caller's PC from the previous frame.
1383 output_offset -= kPCOnStackSize;
1384 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1385 output_frame->SetCallerPc(output_offset, callers_pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001386 DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001387
1388 // Read caller's FP from the previous frame, and set this frame's FP.
1389 output_offset -= kFPOnStackSize;
1390 intptr_t value = output_[frame_index - 1]->GetFp();
1391 output_frame->SetCallerFp(output_offset, value);
1392 intptr_t fp_value = top_address + output_offset;
1393 output_frame->SetFp(fp_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001394 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001396 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001397 // Read the caller's constant pool from the previous frame.
1398 output_offset -= kPointerSize;
1399 value = output_[frame_index - 1]->GetConstantPool();
1400 output_frame->SetCallerConstantPool(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001401 DebugPrintOutputSlot(value, frame_index, output_offset,
1402 "caller's constant_pool\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403 }
1404
1405 // A marker value is used in place of the context.
1406 output_offset -= kPointerSize;
1407 intptr_t context = reinterpret_cast<intptr_t>(
1408 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1409 output_frame->SetFrameSlot(output_offset, context);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001410 DebugPrintOutputSlot(context, frame_index, output_offset,
1411 "context (adaptor sentinel)\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412
1413 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
1414 output_offset -= kPointerSize;
1415 value = reinterpret_cast<intptr_t>(function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001416 WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001417
1418 // Number of incoming arguments.
1419 output_offset -= kPointerSize;
1420 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1421 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001422 DebugPrintOutputSlot(value, frame_index, output_offset, "argc ");
1423 if (trace_scope_ != nullptr) {
1424 PrintF(trace_scope_->file(), "(%d)\n", height - 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001425 }
1426
1427 DCHECK(0 == output_offset);
1428
1429 Builtins* builtins = isolate_->builtins();
1430 Code* adaptor_trampoline =
1431 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
1432 intptr_t pc_value = reinterpret_cast<intptr_t>(
1433 adaptor_trampoline->instruction_start() +
1434 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
1435 output_frame->SetPc(pc_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001436 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001437 intptr_t constant_pool_value =
1438 reinterpret_cast<intptr_t>(adaptor_trampoline->constant_pool());
1439 output_frame->SetConstantPool(constant_pool_value);
1440 }
1441}
1442
1443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001444void Deoptimizer::DoComputeConstructStubFrame(int frame_index) {
1445 TranslatedFrame* translated_frame =
1446 &(translated_state_.frames()[frame_index]);
1447 TranslatedFrame::iterator value_iterator = translated_frame->begin();
1448 int input_index = 0;
1449
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450 Builtins* builtins = isolate_->builtins();
1451 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001452 unsigned height = translated_frame->height();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001453 unsigned height_in_bytes = height * kPointerSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001454 // Skip function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001455 value_iterator++;
1456 input_index++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001457 if (trace_scope_ != NULL) {
1458 PrintF(trace_scope_->file(),
1459 " translating construct stub => height=%d\n", height_in_bytes);
1460 }
1461
1462 unsigned fixed_frame_size = ConstructFrameConstants::kFrameSize;
1463 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1464
1465 // Allocate and store the output frame description.
1466 FrameDescription* output_frame =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001467 new (output_frame_size) FrameDescription(output_frame_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001468 output_frame->SetFrameType(StackFrame::CONSTRUCT);
1469
1470 // Construct stub can not be topmost or bottommost.
1471 DCHECK(frame_index > 0 && frame_index < output_count_ - 1);
1472 DCHECK(output_[frame_index] == NULL);
1473 output_[frame_index] = output_frame;
1474
1475 // The top address of the frame is computed from the previous
1476 // frame's top and this frame's size.
1477 intptr_t top_address;
1478 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1479 output_frame->SetTop(top_address);
1480
1481 // Compute the incoming parameter translation.
1482 int parameter_count = height;
1483 unsigned output_offset = output_frame_size;
1484 for (int i = 0; i < parameter_count; ++i) {
1485 output_offset -= kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001486 // The allocated receiver of a construct stub frame is passed as the
1487 // receiver parameter through the translation. It might be encoding
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001488 // a captured object, override the slot address for a captured object.
1489 WriteTranslatedValueToOutput(
1490 &value_iterator, &input_index, frame_index, output_offset, nullptr,
1491 (i == 0) ? reinterpret_cast<Address>(top_address) : nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001492 }
1493
1494 // Read caller's PC from the previous frame.
1495 output_offset -= kPCOnStackSize;
1496 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1497 output_frame->SetCallerPc(output_offset, callers_pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001498 DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001499
1500 // Read caller's FP from the previous frame, and set this frame's FP.
1501 output_offset -= kFPOnStackSize;
1502 intptr_t value = output_[frame_index - 1]->GetFp();
1503 output_frame->SetCallerFp(output_offset, value);
1504 intptr_t fp_value = top_address + output_offset;
1505 output_frame->SetFp(fp_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001507
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509 // Read the caller's constant pool from the previous frame.
1510 output_offset -= kPointerSize;
1511 value = output_[frame_index - 1]->GetConstantPool();
1512 output_frame->SetCallerConstantPool(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001513 DebugPrintOutputSlot(value, frame_index, output_offset,
1514 "caller's constant_pool\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001515 }
1516
1517 // The context can be gotten from the previous frame.
1518 output_offset -= kPointerSize;
1519 value = output_[frame_index - 1]->GetContext();
1520 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 DebugPrintOutputSlot(value, frame_index, output_offset, "context\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001522
1523 // A marker value is used in place of the function.
1524 output_offset -= kPointerSize;
1525 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
1526 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001527 DebugPrintOutputSlot(value, frame_index, output_offset,
1528 "function (construct sentinel)\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001529
1530 // The output frame reflects a JSConstructStubGeneric frame.
1531 output_offset -= kPointerSize;
1532 value = reinterpret_cast<intptr_t>(construct_stub);
1533 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001534 DebugPrintOutputSlot(value, frame_index, output_offset, "code object\n");
1535
1536 // The allocation site.
1537 output_offset -= kPointerSize;
1538 value = reinterpret_cast<intptr_t>(isolate_->heap()->undefined_value());
1539 output_frame->SetFrameSlot(output_offset, value);
1540 DebugPrintOutputSlot(value, frame_index, output_offset, "allocation site\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001541
1542 // Number of incoming arguments.
1543 output_offset -= kPointerSize;
1544 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1545 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001546 DebugPrintOutputSlot(value, frame_index, output_offset, "argc ");
1547 if (trace_scope_ != nullptr) {
1548 PrintF(trace_scope_->file(), "(%d)\n", height - 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001549 }
1550
1551 // The newly allocated object was passed as receiver in the artificial
1552 // constructor stub environment created by HEnvironment::CopyForInlining().
1553 output_offset -= kPointerSize;
1554 value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
1555 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556 DebugPrintOutputSlot(value, frame_index, output_offset,
1557 "allocated receiver\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001558
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001559 CHECK_EQ(0u, output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001560
1561 intptr_t pc = reinterpret_cast<intptr_t>(
1562 construct_stub->instruction_start() +
1563 isolate_->heap()->construct_stub_deopt_pc_offset()->value());
1564 output_frame->SetPc(pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001565 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001566 intptr_t constant_pool_value =
1567 reinterpret_cast<intptr_t>(construct_stub->constant_pool());
1568 output_frame->SetConstantPool(constant_pool_value);
1569 }
1570}
1571
1572
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001573void Deoptimizer::DoComputeAccessorStubFrame(int frame_index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001574 bool is_setter_stub_frame) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001575 TranslatedFrame* translated_frame =
1576 &(translated_state_.frames()[frame_index]);
1577 TranslatedFrame::iterator value_iterator = translated_frame->begin();
1578 int input_index = 0;
1579
Ben Murdoch097c5b22016-05-18 11:27:45 +01001580 // Skip accessor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001581 value_iterator++;
1582 input_index++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001583 // The receiver (and the implicit return value, if any) are expected in
1584 // registers by the LoadIC/StoreIC, so they don't belong to the output stack
1585 // frame. This means that we have to use a height of 0.
1586 unsigned height = 0;
1587 unsigned height_in_bytes = height * kPointerSize;
1588 const char* kind = is_setter_stub_frame ? "setter" : "getter";
1589 if (trace_scope_ != NULL) {
1590 PrintF(trace_scope_->file(),
1591 " translating %s stub => height=%u\n", kind, height_in_bytes);
1592 }
1593
1594 // We need 1 stack entry for the return address and enough entries for the
1595 // StackFrame::INTERNAL (FP, context, frame type, code object and constant
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001596 // pool (if enabled)- see MacroAssembler::EnterFrame).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001597 // For a setter stub frame we need one additional entry for the implicit
1598 // return value, see StoreStubCompiler::CompileStoreViaSetter.
1599 unsigned fixed_frame_entries =
1600 (StandardFrameConstants::kFixedFrameSize / kPointerSize) + 1 +
1601 (is_setter_stub_frame ? 1 : 0);
1602 unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
1603 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1604
1605 // Allocate and store the output frame description.
1606 FrameDescription* output_frame =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001607 new (output_frame_size) FrameDescription(output_frame_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001608 output_frame->SetFrameType(StackFrame::INTERNAL);
1609
1610 // A frame for an accessor stub can not be the topmost or bottommost one.
1611 CHECK(frame_index > 0 && frame_index < output_count_ - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001612 CHECK_NULL(output_[frame_index]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001613 output_[frame_index] = output_frame;
1614
1615 // The top address of the frame is computed from the previous frame's top and
1616 // this frame's size.
1617 intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1618 output_frame->SetTop(top_address);
1619
1620 unsigned output_offset = output_frame_size;
1621
1622 // Read caller's PC from the previous frame.
1623 output_offset -= kPCOnStackSize;
1624 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1625 output_frame->SetCallerPc(output_offset, callers_pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001626 DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627
1628 // Read caller's FP from the previous frame, and set this frame's FP.
1629 output_offset -= kFPOnStackSize;
1630 intptr_t value = output_[frame_index - 1]->GetFp();
1631 output_frame->SetCallerFp(output_offset, value);
1632 intptr_t fp_value = top_address + output_offset;
1633 output_frame->SetFp(fp_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001634 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001635
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001636 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001637 // Read the caller's constant pool from the previous frame.
1638 output_offset -= kPointerSize;
1639 value = output_[frame_index - 1]->GetConstantPool();
1640 output_frame->SetCallerConstantPool(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001641 DebugPrintOutputSlot(value, frame_index, output_offset,
1642 "caller's constant_pool\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001643 }
1644
1645 // The context can be gotten from the previous frame.
1646 output_offset -= kPointerSize;
1647 value = output_[frame_index - 1]->GetContext();
1648 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001649 DebugPrintOutputSlot(value, frame_index, output_offset, "context\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001650
1651 // A marker value is used in place of the function.
1652 output_offset -= kPointerSize;
1653 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
1654 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001655 DebugPrintOutputSlot(value, frame_index, output_offset, "function ");
1656 if (trace_scope_ != nullptr) {
1657 PrintF(trace_scope_->file(), "(%s sentinel)\n", kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001658 }
1659
1660 // Get Code object from accessor stub.
1661 output_offset -= kPointerSize;
1662 Builtins::Name name = is_setter_stub_frame ?
1663 Builtins::kStoreIC_Setter_ForDeopt :
1664 Builtins::kLoadIC_Getter_ForDeopt;
1665 Code* accessor_stub = isolate_->builtins()->builtin(name);
1666 value = reinterpret_cast<intptr_t>(accessor_stub);
1667 output_frame->SetFrameSlot(output_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001668 DebugPrintOutputSlot(value, frame_index, output_offset, "code object\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001669
1670 // Skip receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 value_iterator++;
1672 input_index++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001673
1674 if (is_setter_stub_frame) {
1675 // The implicit return value was part of the artificial setter stub
1676 // environment.
1677 output_offset -= kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001678 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1679 output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680 }
1681
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001682 CHECK_EQ(0u, output_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001683
1684 Smi* offset = is_setter_stub_frame ?
1685 isolate_->heap()->setter_stub_deopt_pc_offset() :
1686 isolate_->heap()->getter_stub_deopt_pc_offset();
1687 intptr_t pc = reinterpret_cast<intptr_t>(
1688 accessor_stub->instruction_start() + offset->value());
1689 output_frame->SetPc(pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001690 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001691 intptr_t constant_pool_value =
1692 reinterpret_cast<intptr_t>(accessor_stub->constant_pool());
1693 output_frame->SetConstantPool(constant_pool_value);
1694 }
1695}
1696
1697
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001698void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699 //
1700 // FROM TO
1701 // | .... | | .... |
1702 // +-------------------------+ +-------------------------+
1703 // | JSFunction continuation | | JSFunction continuation |
1704 // +-------------------------+ +-------------------------+
1705 // | | saved frame (FP) | | saved frame (FP) |
1706 // | +=========================+<-fpreg +=========================+<-fpreg
1707 // | |constant pool (if ool_cp)| |constant pool (if ool_cp)|
1708 // | +-------------------------+ +-------------------------|
1709 // | | JSFunction context | | JSFunction context |
1710 // v +-------------------------+ +-------------------------|
1711 // | COMPILED_STUB marker | | STUB_FAILURE marker |
1712 // +-------------------------+ +-------------------------+
1713 // | | | caller args.arguments_ |
1714 // | ... | +-------------------------+
1715 // | | | caller args.length_ |
1716 // |-------------------------|<-spreg +-------------------------+
1717 // | caller args pointer |
1718 // +-------------------------+
1719 // | caller stack param 1 |
1720 // parameters in registers +-------------------------+
1721 // and spilled to stack | .... |
1722 // +-------------------------+
1723 // | caller stack param n |
1724 // +-------------------------+<-spreg
1725 // reg = number of parameters
1726 // reg = failure handler address
1727 // reg = saved frame
1728 // reg = JSFunction context
1729 //
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001730 // Caller stack params contain the register parameters to the stub first,
1731 // and then, if the descriptor specifies a constant number of stack
1732 // parameters, the stack parameters as well.
1733
1734 TranslatedFrame* translated_frame =
1735 &(translated_state_.frames()[frame_index]);
1736 TranslatedFrame::iterator value_iterator = translated_frame->begin();
1737 int input_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001738
1739 CHECK(compiled_code_->is_hydrogen_stub());
1740 int major_key = CodeStub::GetMajorKey(compiled_code_);
1741 CodeStubDescriptor descriptor(isolate_, compiled_code_->stub_key());
1742
1743 // The output frame must have room for all pushed register parameters
1744 // and the standard stack frame slots. Include space for an argument
1745 // object to the callee and optionally the space to pass the argument
1746 // object to the stub failure handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 int param_count = descriptor.GetRegisterParameterCount();
1748 int stack_param_count = descriptor.GetStackParameterCount();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001749 // The translated frame contains all of the register parameters
1750 // plus the context.
1751 CHECK_EQ(translated_frame->height(), param_count + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001752 CHECK_GE(param_count, 0);
1753
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001754 int height_in_bytes = kPointerSize * (param_count + stack_param_count) +
1755 sizeof(Arguments) + kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001756 int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
1757 int input_frame_size = input_->GetFrameSize();
1758 int output_frame_size = height_in_bytes + fixed_frame_size;
1759 if (trace_scope_ != NULL) {
1760 PrintF(trace_scope_->file(),
1761 " translating %s => StubFailureTrampolineStub, height=%d\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001762 CodeStub::MajorName(static_cast<CodeStub::Major>(major_key)),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001763 height_in_bytes);
1764 }
1765
1766 // The stub failure trampoline is a single frame.
1767 FrameDescription* output_frame =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001768 new (output_frame_size) FrameDescription(output_frame_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001769 output_frame->SetFrameType(StackFrame::STUB_FAILURE_TRAMPOLINE);
1770 CHECK_EQ(frame_index, 0);
1771 output_[frame_index] = output_frame;
1772
1773 // The top address for the output frame can be computed from the input
1774 // frame pointer and the output frame's height. Subtract space for the
1775 // context and function slots.
1776 Register fp_reg = StubFailureTrampolineFrame::fp_register();
1777 intptr_t top_address = input_->GetRegister(fp_reg.code()) -
1778 StandardFrameConstants::kFixedFrameSizeFromFp - height_in_bytes;
1779 output_frame->SetTop(top_address);
1780
1781 // Read caller's PC (JSFunction continuation) from the input frame.
1782 unsigned input_frame_offset = input_frame_size - kPCOnStackSize;
1783 unsigned output_frame_offset = output_frame_size - kFPOnStackSize;
1784 intptr_t value = input_->GetFrameSlot(input_frame_offset);
1785 output_frame->SetCallerPc(output_frame_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001786 DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1787 "caller's pc\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001788
1789 // Read caller's FP from the input frame, and set this frame's FP.
1790 input_frame_offset -= kFPOnStackSize;
1791 value = input_->GetFrameSlot(input_frame_offset);
1792 output_frame_offset -= kFPOnStackSize;
1793 output_frame->SetCallerFp(output_frame_offset, value);
1794 intptr_t frame_ptr = input_->GetRegister(fp_reg.code());
1795 output_frame->SetRegister(fp_reg.code(), frame_ptr);
1796 output_frame->SetFp(frame_ptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001797 DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1798 "caller's fp\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001799
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001800 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001801 // Read the caller's constant pool from the input frame.
1802 input_frame_offset -= kPointerSize;
1803 value = input_->GetFrameSlot(input_frame_offset);
1804 output_frame_offset -= kPointerSize;
1805 output_frame->SetCallerConstantPool(output_frame_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001806 DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1807 "caller's constant_pool\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001808 }
1809
Ben Murdoch097c5b22016-05-18 11:27:45 +01001810 // Remember where the context will need to be written back from the deopt
1811 // translation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001812 output_frame_offset -= kPointerSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001813 unsigned context_frame_offset = output_frame_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001814
1815 // A marker value is used in place of the function.
1816 output_frame_offset -= kPointerSize;
1817 value = reinterpret_cast<intptr_t>(
1818 Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
1819 output_frame->SetFrameSlot(output_frame_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001820 DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1821 "function (stub failure sentinel)\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001823 intptr_t caller_arg_count = stack_param_count;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001824 bool arg_count_known = !descriptor.stack_parameter_count().is_valid();
1825
1826 // Build the Arguments object for the caller's parameters and a pointer to it.
1827 output_frame_offset -= kPointerSize;
1828 int args_arguments_offset = output_frame_offset;
1829 intptr_t the_hole = reinterpret_cast<intptr_t>(
1830 isolate_->heap()->the_hole_value());
1831 if (arg_count_known) {
1832 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1833 (caller_arg_count - 1) * kPointerSize;
1834 } else {
1835 value = the_hole;
1836 }
1837
1838 output_frame->SetFrameSlot(args_arguments_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001839 DebugPrintOutputSlot(
1840 value, frame_index, args_arguments_offset,
1841 arg_count_known ? "args.arguments\n" : "args.arguments (the hole)\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842
1843 output_frame_offset -= kPointerSize;
1844 int length_frame_offset = output_frame_offset;
1845 value = arg_count_known ? caller_arg_count : the_hole;
1846 output_frame->SetFrameSlot(length_frame_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001847 DebugPrintOutputSlot(
1848 value, frame_index, length_frame_offset,
1849 arg_count_known ? "args.length\n" : "args.length (the hole)\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001850
1851 output_frame_offset -= kPointerSize;
1852 value = frame_ptr + StandardFrameConstants::kCallerSPOffset -
1853 (output_frame_size - output_frame_offset) + kPointerSize;
1854 output_frame->SetFrameSlot(output_frame_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001855 DebugPrintOutputSlot(value, frame_index, output_frame_offset, "args*\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001856
1857 // Copy the register parameters to the failure frame.
1858 int arguments_length_offset = -1;
1859 for (int i = 0; i < param_count; ++i) {
1860 output_frame_offset -= kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001861 WriteTranslatedValueToOutput(&value_iterator, &input_index, 0,
1862 output_frame_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001864 if (!arg_count_known &&
1865 descriptor.GetRegisterParameter(i)
1866 .is(descriptor.stack_parameter_count())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001867 arguments_length_offset = output_frame_offset;
1868 }
1869 }
1870
Ben Murdoch097c5b22016-05-18 11:27:45 +01001871 Object* maybe_context = value_iterator->GetRawValue();
1872 CHECK(maybe_context->IsContext());
1873 Register context_reg = StubFailureTrampolineFrame::context_register();
1874 value = reinterpret_cast<intptr_t>(maybe_context);
1875 output_frame->SetRegister(context_reg.code(), value);
1876 output_frame->SetFrameSlot(context_frame_offset, value);
1877 DebugPrintOutputSlot(value, frame_index, context_frame_offset, "context\n");
1878 ++value_iterator;
1879
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001880 // Copy constant stack parameters to the failure frame. If the number of stack
1881 // parameters is not known in the descriptor, the arguments object is the way
1882 // to access them.
1883 for (int i = 0; i < stack_param_count; i++) {
1884 output_frame_offset -= kPointerSize;
1885 Object** stack_parameter = reinterpret_cast<Object**>(
1886 frame_ptr + StandardFrameConstants::kCallerSPOffset +
1887 (stack_param_count - i - 1) * kPointerSize);
1888 value = reinterpret_cast<intptr_t>(*stack_parameter);
1889 output_frame->SetFrameSlot(output_frame_offset, value);
1890 DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1891 "stack parameter\n");
1892 }
1893
1894 CHECK_EQ(0u, output_frame_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001895
1896 if (!arg_count_known) {
1897 CHECK_GE(arguments_length_offset, 0);
1898 // We know it's a smi because 1) the code stub guarantees the stack
1899 // parameter count is in smi range, and 2) the DoTranslateCommand in the
1900 // parameter loop above translated that to a tagged value.
1901 Smi* smi_caller_arg_count = reinterpret_cast<Smi*>(
1902 output_frame->GetFrameSlot(arguments_length_offset));
1903 caller_arg_count = smi_caller_arg_count->value();
1904 output_frame->SetFrameSlot(length_frame_offset, caller_arg_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001905 DebugPrintOutputSlot(caller_arg_count, frame_index, length_frame_offset,
1906 "args.length\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1908 (caller_arg_count - 1) * kPointerSize;
1909 output_frame->SetFrameSlot(args_arguments_offset, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001910 DebugPrintOutputSlot(value, frame_index, args_arguments_offset,
1911 "args.arguments");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001912 }
1913
1914 // Copy the double registers from the input into the output frame.
1915 CopyDoubleRegisters(output_frame);
1916
1917 // Fill registers containing handler and number of parameters.
1918 SetPlatformCompiledStubRegisters(output_frame, &descriptor);
1919
1920 // Compute this frame's PC, state, and continuation.
1921 Code* trampoline = NULL;
1922 StubFunctionMode function_mode = descriptor.function_mode();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001923 StubFailureTrampolineStub(isolate_, function_mode)
1924 .FindCodeInCache(&trampoline);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001925 DCHECK(trampoline != NULL);
1926 output_frame->SetPc(reinterpret_cast<intptr_t>(
1927 trampoline->instruction_start()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001928 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001929 Register constant_pool_reg =
1930 StubFailureTrampolineFrame::constant_pool_pointer_register();
1931 intptr_t constant_pool_value =
1932 reinterpret_cast<intptr_t>(trampoline->constant_pool());
1933 output_frame->SetConstantPool(constant_pool_value);
1934 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1935 }
1936 output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
1937 Code* notify_failure =
1938 isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles);
1939 output_frame->SetContinuation(
1940 reinterpret_cast<intptr_t>(notify_failure->entry()));
1941}
1942
1943
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001944void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
1945 DCHECK_NE(DEBUGGER, bailout_type_);
1946
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001947 // Walk to the last JavaScript output frame to find out if it has
1948 // adapted arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001949 for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
1950 if (frame_index != 0) it->Advance();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001951 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001952 translated_state_.Prepare(it->frame()->has_adapted_arguments(), stack_fp_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001954 for (auto& materialization : values_to_materialize_) {
1955 Handle<Object> value = materialization.value_->GetValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001956
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001957 if (trace_scope_ != nullptr) {
1958 PrintF("Materialization [0x%08" V8PRIxPTR "] <- 0x%08" V8PRIxPTR " ; ",
1959 reinterpret_cast<intptr_t>(materialization.output_slot_address_),
1960 reinterpret_cast<intptr_t>(*value));
1961 value->ShortPrint(trace_scope_->file());
1962 PrintF(trace_scope_->file(), "\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001963 }
1964
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001965 *(reinterpret_cast<intptr_t*>(materialization.output_slot_address_)) =
1966 reinterpret_cast<intptr_t>(*value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001967 }
1968
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001969 isolate_->materialized_object_store()->Remove(stack_fp_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001970}
1971
1972
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001973void Deoptimizer::WriteTranslatedValueToOutput(
1974 TranslatedFrame::iterator* iterator, int* input_index, int frame_index,
1975 unsigned output_offset, const char* debug_hint_string,
1976 Address output_address_for_materialization) {
1977 Object* value = (*iterator)->GetRawValue();
1978
1979 WriteValueToOutput(value, *input_index, frame_index, output_offset,
1980 debug_hint_string);
1981
1982 if (value == isolate_->heap()->arguments_marker()) {
1983 Address output_address =
1984 reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
1985 output_offset;
1986 if (output_address_for_materialization == nullptr) {
1987 output_address_for_materialization = output_address;
1988 }
1989 values_to_materialize_.push_back(
1990 {output_address_for_materialization, *iterator});
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001991 }
1992
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001993 (*iterator)++;
1994 (*input_index)++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001995}
1996
1997
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001998void Deoptimizer::WriteValueToOutput(Object* value, int input_index,
1999 int frame_index, unsigned output_offset,
2000 const char* debug_hint_string) {
2001 output_[frame_index]->SetFrameSlot(output_offset,
2002 reinterpret_cast<intptr_t>(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002003
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002004 if (trace_scope_ != nullptr) {
2005 DebugPrintOutputSlot(reinterpret_cast<intptr_t>(value), frame_index,
2006 output_offset, debug_hint_string);
2007 value->ShortPrint(trace_scope_->file());
2008 PrintF(trace_scope_->file(), " (input #%d)\n", input_index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002009 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002010}
2011
2012
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002013void Deoptimizer::DebugPrintOutputSlot(intptr_t value, int frame_index,
2014 unsigned output_offset,
2015 const char* debug_hint_string) {
2016 if (trace_scope_ != nullptr) {
2017 Address output_address =
2018 reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
2019 output_offset;
2020 PrintF(trace_scope_->file(),
2021 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s",
2022 reinterpret_cast<intptr_t>(output_address), output_offset, value,
2023 debug_hint_string == nullptr ? "" : debug_hint_string);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002024 }
2025}
2026
2027
Ben Murdochb0fe1622011-05-05 13:52:32 +01002028unsigned Deoptimizer::ComputeInputFrameSize() const {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002029 unsigned fixed_size = StandardFrameConstants::kFixedFrameSize;
2030 if (!function_->IsSmi()) {
2031 fixed_size += ComputeIncomingArgumentSize(function_->shared());
2032 } else {
2033 CHECK_EQ(Smi::cast(function_), Smi::FromInt(StackFrame::STUB));
2034 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002035 // The fp-to-sp delta already takes the context, constant pool pointer and the
2036 // function into account so we have to avoid double counting them.
2037 unsigned result = fixed_size + fp_to_sp_delta_ -
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002038 StandardFrameConstants::kFixedFrameSizeFromFp;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002039 if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
2040 unsigned stack_slots = compiled_code_->stack_slots();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002041 unsigned outgoing_size =
2042 ComputeOutgoingArgumentSize(compiled_code_, bailout_id_);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002043 CHECK(result ==
2044 fixed_size + (stack_slots * kPointerSize) -
2045 StandardFrameConstants::kFixedFrameSize + outgoing_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002046 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002047 return result;
2048}
2049
Ben Murdoch097c5b22016-05-18 11:27:45 +01002050// static
2051unsigned Deoptimizer::ComputeJavascriptFixedSize(SharedFunctionInfo* shared) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002052 // The fixed part of the frame consists of the return address, frame
2053 // pointer, function, context, and all the incoming arguments.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002054 return ComputeIncomingArgumentSize(shared) +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002055 StandardFrameConstants::kFixedFrameSize;
2056}
2057
Ben Murdoch097c5b22016-05-18 11:27:45 +01002058// static
2059unsigned Deoptimizer::ComputeInterpretedFixedSize(SharedFunctionInfo* shared) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002060 // The fixed part of the frame consists of the return address, frame
2061 // pointer, function, context, new.target, bytecode offset and all the
2062 // incoming arguments.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002063 return ComputeIncomingArgumentSize(shared) +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002064 InterpreterFrameConstants::kFixedFrameSize;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002065}
2066
Ben Murdoch097c5b22016-05-18 11:27:45 +01002067// static
2068unsigned Deoptimizer::ComputeIncomingArgumentSize(SharedFunctionInfo* shared) {
2069 return (shared->internal_formal_parameter_count() + 1) * kPointerSize;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002070}
2071
2072
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002073// static
2074unsigned Deoptimizer::ComputeOutgoingArgumentSize(Code* code,
2075 unsigned bailout_id) {
2076 DeoptimizationInputData* data =
2077 DeoptimizationInputData::cast(code->deoptimization_data());
2078 unsigned height = data->ArgumentsStackHeight(bailout_id)->value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002079 return height * kPointerSize;
2080}
2081
2082
2083Object* Deoptimizer::ComputeLiteral(int index) const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002084 DeoptimizationInputData* data =
2085 DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002086 FixedArray* literals = data->LiteralArray();
2087 return literals->get(index);
2088}
2089
2090
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002091void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
2092 BailoutType type,
2093 int max_entry_id) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002094 // We cannot run this if the serializer is enabled because this will
2095 // cause us to emit relocation information for the external
2096 // references. This is fine because the deoptimizer's code section
2097 // isn't meant to be serialized at all.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002098 CHECK(type == EAGER || type == SOFT || type == LAZY);
2099 DeoptimizerData* data = isolate->deoptimizer_data();
2100 int entry_count = data->deopt_entry_code_entries_[type];
2101 if (max_entry_id < entry_count) return;
2102 entry_count = Max(entry_count, Deoptimizer::kMinNumberOfEntries);
2103 while (max_entry_id >= entry_count) entry_count *= 2;
2104 CHECK(entry_count <= Deoptimizer::kMaxNumberOfEntries);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002106 MacroAssembler masm(isolate, NULL, 16 * KB, CodeObjectRequired::kYes);
Steve Block44f0eee2011-05-26 01:26:41 +01002107 masm.set_emit_debug_code(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002108 GenerateDeoptimizationEntries(&masm, entry_count, type);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002109 CodeDesc desc;
2110 masm.GetCode(&desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002111 DCHECK(!RelocInfo::RequiresRelocation(desc));
Ben Murdochb0fe1622011-05-05 13:52:32 +01002112
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002113 MemoryChunk* chunk = data->deopt_entry_code_[type];
2114 CHECK(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
2115 desc.instr_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002116 if (!chunk->CommitArea(desc.instr_size)) {
2117 V8::FatalProcessOutOfMemory(
2118 "Deoptimizer::EnsureCodeForDeoptimizationEntry");
2119 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002120 CopyBytes(chunk->area_start(), desc.buffer,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002121 static_cast<size_t>(desc.instr_size));
2122 Assembler::FlushICache(isolate, chunk->area_start(), desc.instr_size);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002123
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002124 data->deopt_entry_code_entries_[type] = entry_count;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002125}
2126
Ben Murdoch097c5b22016-05-18 11:27:45 +01002127FrameDescription::FrameDescription(uint32_t frame_size, int parameter_count)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002128 : frame_size_(frame_size),
Ben Murdoch097c5b22016-05-18 11:27:45 +01002129 parameter_count_(parameter_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01002130 top_(kZapUint32),
2131 pc_(kZapUint32),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002132 fp_(kZapUint32),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002133 context_(kZapUint32),
2134 constant_pool_(kZapUint32) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002135 // Zap all the registers.
2136 for (int r = 0; r < Register::kNumRegisters; r++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002137 // TODO(jbramley): It isn't safe to use kZapUint32 here. If the register
2138 // isn't used before the next safepoint, the GC will try to scan it as a
2139 // tagged value. kZapUint32 looks like a valid tagged pointer, but it isn't.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002140 SetRegister(r, kZapUint32);
2141 }
2142
2143 // Zap all the slots.
2144 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
2145 SetFrameSlot(o, kZapUint32);
2146 }
2147}
2148
2149
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002150int FrameDescription::ComputeFixedSize() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002151 if (type_ == StackFrame::INTERPRETED) {
2152 return InterpreterFrameConstants::kFixedFrameSize +
Ben Murdoch097c5b22016-05-18 11:27:45 +01002153 parameter_count() * kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002154 } else {
2155 return StandardFrameConstants::kFixedFrameSize +
Ben Murdoch097c5b22016-05-18 11:27:45 +01002156 parameter_count() * kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002157 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002158}
2159
2160
2161unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002162 if (slot_index >= 0) {
2163 // Local or spill slots. Skip the fixed part of the frame
2164 // including all arguments.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002165 unsigned base = GetFrameSize() - ComputeFixedSize();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002166 return base - ((slot_index + 1) * kPointerSize);
2167 } else {
2168 // Incoming parameter.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002169 int arg_size = parameter_count() * kPointerSize;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002170 unsigned base = GetFrameSize() - arg_size;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002171 return base - ((slot_index + 1) * kPointerSize);
2172 }
2173}
2174
2175
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002176void TranslationBuffer::Add(int32_t value, Zone* zone) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002177 // This wouldn't handle kMinInt correctly if it ever encountered it.
2178 DCHECK(value != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002179 // Encode the sign bit in the least significant bit.
2180 bool is_negative = (value < 0);
2181 uint32_t bits = ((is_negative ? -value : value) << 1) |
2182 static_cast<int32_t>(is_negative);
2183 // Encode the individual bytes using the least significant bit of
2184 // each byte to indicate whether or not more bytes follow.
2185 do {
2186 uint32_t next = bits >> 7;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002187 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002188 bits = next;
2189 } while (bits != 0);
2190}
2191
2192
2193int32_t TranslationIterator::Next() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002194 // Run through the bytes until we reach one with a least significant
2195 // bit of zero (marks the end).
2196 uint32_t bits = 0;
2197 for (int i = 0; true; i += 7) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002198 DCHECK(HasNext());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002199 uint8_t next = buffer_->get(index_++);
2200 bits |= (next >> 1) << i;
2201 if ((next & 1) == 0) break;
2202 }
2203 // The bits encode the sign in the least significant bit.
2204 bool is_negative = (bits & 1) == 1;
2205 int32_t result = bits >> 1;
2206 return is_negative ? -result : result;
2207}
2208
2209
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002210Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002211 int length = contents_.length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002212 Handle<ByteArray> result = factory->NewByteArray(length, TENURED);
2213 MemCopy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002214 return result;
2215}
2216
2217
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002218void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002219 buffer_->Add(CONSTRUCT_STUB_FRAME, zone());
2220 buffer_->Add(literal_id, zone());
2221 buffer_->Add(height, zone());
2222}
2223
2224
2225void Translation::BeginGetterStubFrame(int literal_id) {
2226 buffer_->Add(GETTER_STUB_FRAME, zone());
2227 buffer_->Add(literal_id, zone());
2228}
2229
2230
2231void Translation::BeginSetterStubFrame(int literal_id) {
2232 buffer_->Add(SETTER_STUB_FRAME, zone());
2233 buffer_->Add(literal_id, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002234}
2235
2236
2237void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002238 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone());
2239 buffer_->Add(literal_id, zone());
2240 buffer_->Add(height, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002241}
2242
2243
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002244void Translation::BeginJSFrame(BailoutId node_id,
2245 int literal_id,
2246 unsigned height) {
2247 buffer_->Add(JS_FRAME, zone());
2248 buffer_->Add(node_id.ToInt(), zone());
2249 buffer_->Add(literal_id, zone());
2250 buffer_->Add(height, zone());
2251}
2252
2253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002254void Translation::BeginInterpretedFrame(BailoutId bytecode_offset,
2255 int literal_id, unsigned height) {
2256 buffer_->Add(INTERPRETED_FRAME, zone());
2257 buffer_->Add(bytecode_offset.ToInt(), zone());
2258 buffer_->Add(literal_id, zone());
2259 buffer_->Add(height, zone());
2260}
2261
2262
2263void Translation::BeginCompiledStubFrame(int height) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002264 buffer_->Add(COMPILED_STUB_FRAME, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002265 buffer_->Add(height, zone());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002266}
2267
2268
2269void Translation::BeginArgumentsObject(int args_length) {
2270 buffer_->Add(ARGUMENTS_OBJECT, zone());
2271 buffer_->Add(args_length, zone());
2272}
2273
2274
2275void Translation::BeginCapturedObject(int length) {
2276 buffer_->Add(CAPTURED_OBJECT, zone());
2277 buffer_->Add(length, zone());
2278}
2279
2280
2281void Translation::DuplicateObject(int object_index) {
2282 buffer_->Add(DUPLICATED_OBJECT, zone());
2283 buffer_->Add(object_index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002284}
2285
2286
2287void Translation::StoreRegister(Register reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002288 buffer_->Add(REGISTER, zone());
2289 buffer_->Add(reg.code(), zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002290}
2291
2292
2293void Translation::StoreInt32Register(Register reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002294 buffer_->Add(INT32_REGISTER, zone());
2295 buffer_->Add(reg.code(), zone());
2296}
2297
2298
2299void Translation::StoreUint32Register(Register reg) {
2300 buffer_->Add(UINT32_REGISTER, zone());
2301 buffer_->Add(reg.code(), zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002302}
2303
2304
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002305void Translation::StoreBoolRegister(Register reg) {
2306 buffer_->Add(BOOL_REGISTER, zone());
2307 buffer_->Add(reg.code(), zone());
2308}
2309
2310
Ben Murdochb0fe1622011-05-05 13:52:32 +01002311void Translation::StoreDoubleRegister(DoubleRegister reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002312 buffer_->Add(DOUBLE_REGISTER, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002313 buffer_->Add(reg.code(), zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002314}
2315
2316
2317void Translation::StoreStackSlot(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 buffer_->Add(STACK_SLOT, zone());
2319 buffer_->Add(index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002320}
2321
2322
2323void Translation::StoreInt32StackSlot(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002324 buffer_->Add(INT32_STACK_SLOT, zone());
2325 buffer_->Add(index, zone());
2326}
2327
2328
2329void Translation::StoreUint32StackSlot(int index) {
2330 buffer_->Add(UINT32_STACK_SLOT, zone());
2331 buffer_->Add(index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002332}
2333
2334
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002335void Translation::StoreBoolStackSlot(int index) {
2336 buffer_->Add(BOOL_STACK_SLOT, zone());
2337 buffer_->Add(index, zone());
2338}
2339
2340
Ben Murdochb0fe1622011-05-05 13:52:32 +01002341void Translation::StoreDoubleStackSlot(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002342 buffer_->Add(DOUBLE_STACK_SLOT, zone());
2343 buffer_->Add(index, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002344}
2345
2346
2347void Translation::StoreLiteral(int literal_id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002348 buffer_->Add(LITERAL, zone());
2349 buffer_->Add(literal_id, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002350}
2351
2352
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002353void Translation::StoreArgumentsObject(bool args_known,
2354 int args_index,
2355 int args_length) {
2356 buffer_->Add(ARGUMENTS_OBJECT, zone());
2357 buffer_->Add(args_known, zone());
2358 buffer_->Add(args_index, zone());
2359 buffer_->Add(args_length, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002360}
2361
2362
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002363void Translation::StoreJSFrameFunction() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002364 StoreStackSlot((StandardFrameConstants::kCallerPCOffset -
2365 StandardFrameConstants::kMarkerOffset) /
2366 kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002367}
2368
Ben Murdochb0fe1622011-05-05 13:52:32 +01002369int Translation::NumberOfOperandsFor(Opcode opcode) {
2370 switch (opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002371 case GETTER_STUB_FRAME:
2372 case SETTER_STUB_FRAME:
2373 case DUPLICATED_OBJECT:
Ben Murdochb0fe1622011-05-05 13:52:32 +01002374 case ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002375 case CAPTURED_OBJECT:
Ben Murdochb0fe1622011-05-05 13:52:32 +01002376 case REGISTER:
2377 case INT32_REGISTER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002378 case UINT32_REGISTER:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002379 case BOOL_REGISTER:
Ben Murdochb0fe1622011-05-05 13:52:32 +01002380 case DOUBLE_REGISTER:
2381 case STACK_SLOT:
2382 case INT32_STACK_SLOT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002383 case UINT32_STACK_SLOT:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002384 case BOOL_STACK_SLOT:
Ben Murdochb0fe1622011-05-05 13:52:32 +01002385 case DOUBLE_STACK_SLOT:
2386 case LITERAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002387 case COMPILED_STUB_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +01002388 return 1;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002389 case BEGIN:
2390 case ARGUMENTS_ADAPTOR_FRAME:
2391 case CONSTRUCT_STUB_FRAME:
2392 return 2;
2393 case JS_FRAME:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002394 case INTERPRETED_FRAME:
Ben Murdochb0fe1622011-05-05 13:52:32 +01002395 return 3;
2396 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002397 FATAL("Unexpected translation type");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002398 return -1;
2399}
2400
2401
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002402#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002403
2404const char* Translation::StringFor(Opcode opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002405#define TRANSLATION_OPCODE_CASE(item) case item: return #item;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002406 switch (opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002407 TRANSLATION_OPCODE_LIST(TRANSLATION_OPCODE_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002408 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002409#undef TRANSLATION_OPCODE_CASE
Ben Murdochb0fe1622011-05-05 13:52:32 +01002410 UNREACHABLE();
2411 return "";
2412}
2413
2414#endif
2415
2416
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002417Handle<FixedArray> MaterializedObjectStore::Get(Address fp) {
2418 int index = StackIdToIndex(fp);
2419 if (index == -1) {
2420 return Handle<FixedArray>::null();
2421 }
2422 Handle<FixedArray> array = GetStackEntries();
2423 CHECK_GT(array->length(), index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002424 return Handle<FixedArray>::cast(Handle<Object>(array->get(index), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002425}
2426
2427
2428void MaterializedObjectStore::Set(Address fp,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002429 Handle<FixedArray> materialized_objects) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002430 int index = StackIdToIndex(fp);
2431 if (index == -1) {
2432 index = frame_fps_.length();
2433 frame_fps_.Add(fp);
2434 }
2435
2436 Handle<FixedArray> array = EnsureStackEntries(index + 1);
2437 array->set(index, *materialized_objects);
2438}
2439
2440
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002441bool MaterializedObjectStore::Remove(Address fp) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002442 int index = StackIdToIndex(fp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002443 if (index == -1) {
2444 return false;
2445 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002446 CHECK_GE(index, 0);
2447
2448 frame_fps_.Remove(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002449 FixedArray* array = isolate()->heap()->materialized_objects();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002450 CHECK_LT(index, array->length());
2451 for (int i = index; i < frame_fps_.length(); i++) {
2452 array->set(i, array->get(i + 1));
2453 }
2454 array->set(frame_fps_.length(), isolate()->heap()->undefined_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002455 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456}
2457
2458
2459int MaterializedObjectStore::StackIdToIndex(Address fp) {
2460 for (int i = 0; i < frame_fps_.length(); i++) {
2461 if (frame_fps_[i] == fp) {
2462 return i;
2463 }
2464 }
2465 return -1;
2466}
2467
2468
2469Handle<FixedArray> MaterializedObjectStore::GetStackEntries() {
2470 return Handle<FixedArray>(isolate()->heap()->materialized_objects());
2471}
2472
2473
2474Handle<FixedArray> MaterializedObjectStore::EnsureStackEntries(int length) {
2475 Handle<FixedArray> array = GetStackEntries();
2476 if (array->length() >= length) {
2477 return array;
2478 }
2479
2480 int new_length = length > 10 ? length : 10;
2481 if (new_length < 2 * array->length()) {
2482 new_length = 2 * array->length();
2483 }
2484
2485 Handle<FixedArray> new_array =
2486 isolate()->factory()->NewFixedArray(new_length, TENURED);
2487 for (int i = 0; i < array->length(); i++) {
2488 new_array->set(i, array->get(i));
2489 }
2490 for (int i = array->length(); i < length; i++) {
2491 new_array->set(i, isolate()->heap()->undefined_value());
2492 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002493 isolate()->heap()->SetRootMaterializedObjects(*new_array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002494 return new_array;
2495}
2496
Ben Murdoch097c5b22016-05-18 11:27:45 +01002497namespace {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002498
Ben Murdoch097c5b22016-05-18 11:27:45 +01002499Handle<Object> GetValueForDebugger(TranslatedFrame::iterator it,
2500 Isolate* isolate) {
2501 if (it->GetRawValue() == isolate->heap()->arguments_marker()) {
2502 if (!it->IsMaterializableByDebugger()) {
2503 return isolate->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002505 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002506 return it->GetValue();
2507}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002508
Ben Murdoch097c5b22016-05-18 11:27:45 +01002509int ComputeSourcePosition(Handle<SharedFunctionInfo> shared,
2510 BailoutId node_id) {
2511 if (shared->HasBytecodeArray()) {
2512 BytecodeArray* bytecodes = shared->bytecode_array();
2513 return bytecodes->SourcePosition(node_id.ToInt());
2514 } else {
2515 Code* non_optimized_code = shared->code();
2516 FixedArray* raw_data = non_optimized_code->deoptimization_data();
2517 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
2518 unsigned pc_and_state = Deoptimizer::GetOutputInfo(data, node_id, *shared);
2519 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
2520 return non_optimized_code->SourcePosition(pc_offset);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002521 }
2522}
2523
Ben Murdoch097c5b22016-05-18 11:27:45 +01002524} // namespace
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002525
Ben Murdoch097c5b22016-05-18 11:27:45 +01002526DeoptimizedFrameInfo::DeoptimizedFrameInfo(TranslatedState* state,
2527 TranslatedState::iterator frame_it,
2528 Isolate* isolate) {
2529 // If the previous frame is an adaptor frame, we will take the parameters
2530 // from there.
2531 TranslatedState::iterator parameter_frame = frame_it;
2532 if (parameter_frame != state->begin()) {
2533 parameter_frame--;
2534 }
2535 int parameter_count;
2536 if (parameter_frame->kind() == TranslatedFrame::kArgumentsAdaptor) {
2537 parameter_count = parameter_frame->height() - 1; // Ignore the receiver.
2538 } else {
2539 parameter_frame = frame_it;
2540 parameter_count =
2541 frame_it->shared_info()->internal_formal_parameter_count();
2542 }
2543 TranslatedFrame::iterator parameter_it = parameter_frame->begin();
2544 parameter_it++; // Skip the function.
2545 parameter_it++; // Skip the receiver.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002546
Ben Murdoch097c5b22016-05-18 11:27:45 +01002547 // Figure out whether there is a construct stub frame on top of
2548 // the parameter frame.
2549 has_construct_stub_ =
2550 parameter_frame != state->begin() &&
2551 (parameter_frame - 1)->kind() == TranslatedFrame::kConstructStub;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002552
Ben Murdoch097c5b22016-05-18 11:27:45 +01002553 source_position_ =
2554 ComputeSourcePosition(frame_it->shared_info(), frame_it->node_id());
2555
2556 TranslatedFrame::iterator value_it = frame_it->begin();
2557 // Get the function. Note that this might materialize the function.
2558 // In case the debugger mutates this value, we should deoptimize
2559 // the function and remember the value in the materialized value store.
2560 function_ = Handle<JSFunction>::cast(value_it->GetValue());
2561
2562 parameters_.resize(static_cast<size_t>(parameter_count));
2563 for (int i = 0; i < parameter_count; i++) {
2564 Handle<Object> parameter = GetValueForDebugger(parameter_it, isolate);
2565 SetParameter(i, parameter);
2566 parameter_it++;
2567 }
2568
2569 // Skip the function, the receiver and the arguments.
2570 int skip_count =
2571 frame_it->shared_info()->internal_formal_parameter_count() + 2;
2572 TranslatedFrame::iterator stack_it = frame_it->begin();
2573 for (int i = 0; i < skip_count; i++) {
2574 stack_it++;
2575 }
2576
2577 // Get the context.
2578 context_ = GetValueForDebugger(stack_it, isolate);
2579 stack_it++;
2580
2581 // Get the expression stack.
2582 int stack_height = frame_it->height();
2583 if (frame_it->kind() == TranslatedFrame::kFunction ||
2584 frame_it->kind() == TranslatedFrame::kInterpretedFunction) {
2585 // For full-code frames, we should not count the context.
2586 // For interpreter frames, we should not count the accumulator.
2587 // TODO(jarin): Clean up the indexing in translated frames.
2588 stack_height--;
2589 }
2590 expression_stack_.resize(static_cast<size_t>(stack_height));
2591 for (int i = 0; i < stack_height; i++) {
2592 Handle<Object> expression = GetValueForDebugger(stack_it, isolate);
2593 SetExpression(i, expression);
2594 stack_it++;
2595 }
2596
2597 // For interpreter frame, skip the accumulator.
2598 if (frame_it->kind() == TranslatedFrame::kInterpretedFunction) {
2599 stack_it++;
2600 }
2601 CHECK(stack_it == frame_it->end());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002602}
2603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002604
2605const char* Deoptimizer::GetDeoptReason(DeoptReason deopt_reason) {
2606 DCHECK(deopt_reason < kLastDeoptReason);
2607#define DEOPT_MESSAGES_TEXTS(C, T) T,
2608 static const char* deopt_messages_[] = {
2609 DEOPT_MESSAGES_LIST(DEOPT_MESSAGES_TEXTS)};
2610#undef DEOPT_MESSAGES_TEXTS
2611 return deopt_messages_[deopt_reason];
2612}
2613
2614
2615Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, Address pc) {
2616 SourcePosition last_position = SourcePosition::Unknown();
2617 Deoptimizer::DeoptReason last_reason = Deoptimizer::kNoReason;
2618 int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
2619 RelocInfo::ModeMask(RelocInfo::POSITION);
2620 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2621 RelocInfo* info = it.rinfo();
2622 if (info->pc() >= pc) return DeoptInfo(last_position, NULL, last_reason);
2623 if (info->rmode() == RelocInfo::POSITION) {
2624 int raw_position = static_cast<int>(info->data());
2625 last_position = raw_position ? SourcePosition::FromRaw(raw_position)
2626 : SourcePosition::Unknown();
2627 } else if (info->rmode() == RelocInfo::DEOPT_REASON) {
2628 last_reason = static_cast<Deoptimizer::DeoptReason>(info->data());
2629 }
2630 }
2631 return DeoptInfo(SourcePosition::Unknown(), NULL, Deoptimizer::kNoReason);
2632}
2633
2634
2635// static
2636TranslatedValue TranslatedValue::NewArgumentsObject(TranslatedState* container,
2637 int length,
2638 int object_index) {
2639 TranslatedValue slot(container, kArgumentsObject);
2640 slot.materialization_info_ = {object_index, length};
2641 return slot;
2642}
2643
2644
2645// static
2646TranslatedValue TranslatedValue::NewDeferredObject(TranslatedState* container,
2647 int length,
2648 int object_index) {
2649 TranslatedValue slot(container, kCapturedObject);
2650 slot.materialization_info_ = {object_index, length};
2651 return slot;
2652}
2653
2654
2655// static
2656TranslatedValue TranslatedValue::NewDuplicateObject(TranslatedState* container,
2657 int id) {
2658 TranslatedValue slot(container, kDuplicatedObject);
2659 slot.materialization_info_ = {id, -1};
2660 return slot;
2661}
2662
2663
2664// static
2665TranslatedValue TranslatedValue::NewDouble(TranslatedState* container,
2666 double value) {
2667 TranslatedValue slot(container, kDouble);
2668 slot.double_value_ = value;
2669 return slot;
2670}
2671
2672
2673// static
2674TranslatedValue TranslatedValue::NewInt32(TranslatedState* container,
2675 int32_t value) {
2676 TranslatedValue slot(container, kInt32);
2677 slot.int32_value_ = value;
2678 return slot;
2679}
2680
2681
2682// static
2683TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container,
2684 uint32_t value) {
2685 TranslatedValue slot(container, kUInt32);
2686 slot.uint32_value_ = value;
2687 return slot;
2688}
2689
2690
2691// static
2692TranslatedValue TranslatedValue::NewBool(TranslatedState* container,
2693 uint32_t value) {
2694 TranslatedValue slot(container, kBoolBit);
2695 slot.uint32_value_ = value;
2696 return slot;
2697}
2698
2699
2700// static
2701TranslatedValue TranslatedValue::NewTagged(TranslatedState* container,
2702 Object* literal) {
2703 TranslatedValue slot(container, kTagged);
2704 slot.raw_literal_ = literal;
2705 return slot;
2706}
2707
2708
2709// static
2710TranslatedValue TranslatedValue::NewInvalid(TranslatedState* container) {
2711 return TranslatedValue(container, kInvalid);
2712}
2713
2714
2715Isolate* TranslatedValue::isolate() const { return container_->isolate(); }
2716
2717
2718Object* TranslatedValue::raw_literal() const {
2719 DCHECK_EQ(kTagged, kind());
2720 return raw_literal_;
2721}
2722
2723
2724int32_t TranslatedValue::int32_value() const {
2725 DCHECK_EQ(kInt32, kind());
2726 return int32_value_;
2727}
2728
2729
2730uint32_t TranslatedValue::uint32_value() const {
2731 DCHECK(kind() == kUInt32 || kind() == kBoolBit);
2732 return uint32_value_;
2733}
2734
2735
2736double TranslatedValue::double_value() const {
2737 DCHECK_EQ(kDouble, kind());
2738 return double_value_;
2739}
2740
2741
2742int TranslatedValue::object_length() const {
2743 DCHECK(kind() == kArgumentsObject || kind() == kCapturedObject);
2744 return materialization_info_.length_;
2745}
2746
2747
2748int TranslatedValue::object_index() const {
2749 DCHECK(kind() == kArgumentsObject || kind() == kCapturedObject ||
2750 kind() == kDuplicatedObject);
2751 return materialization_info_.id_;
2752}
2753
2754
2755Object* TranslatedValue::GetRawValue() const {
2756 // If we have a value, return it.
2757 Handle<Object> result_handle;
2758 if (value_.ToHandle(&result_handle)) {
2759 return *result_handle;
2760 }
2761
2762 // Otherwise, do a best effort to get the value without allocation.
2763 switch (kind()) {
2764 case kTagged:
2765 return raw_literal();
2766
2767 case kInt32: {
2768 bool is_smi = Smi::IsValid(int32_value());
2769 if (is_smi) {
2770 return Smi::FromInt(int32_value());
2771 }
2772 break;
2773 }
2774
2775 case kUInt32: {
2776 bool is_smi = (uint32_value() <= static_cast<uintptr_t>(Smi::kMaxValue));
2777 if (is_smi) {
2778 return Smi::FromInt(static_cast<int32_t>(uint32_value()));
2779 }
2780 break;
2781 }
2782
2783 case kBoolBit: {
2784 if (uint32_value() == 0) {
2785 return isolate()->heap()->false_value();
2786 } else {
2787 CHECK_EQ(1U, uint32_value());
2788 return isolate()->heap()->true_value();
2789 }
2790 }
2791
2792 default:
2793 break;
2794 }
2795
2796 // If we could not get the value without allocation, return the arguments
2797 // marker.
2798 return isolate()->heap()->arguments_marker();
2799}
2800
2801
2802Handle<Object> TranslatedValue::GetValue() {
2803 Handle<Object> result;
2804 // If we already have a value, then get it.
2805 if (value_.ToHandle(&result)) return result;
2806
2807 // Otherwise we have to materialize.
2808 switch (kind()) {
2809 case TranslatedValue::kTagged:
2810 case TranslatedValue::kInt32:
2811 case TranslatedValue::kUInt32:
2812 case TranslatedValue::kBoolBit:
2813 case TranslatedValue::kDouble: {
2814 MaterializeSimple();
2815 return value_.ToHandleChecked();
2816 }
2817
2818 case TranslatedValue::kArgumentsObject:
2819 case TranslatedValue::kCapturedObject:
2820 case TranslatedValue::kDuplicatedObject:
2821 return container_->MaterializeObjectAt(object_index());
2822
2823 case TranslatedValue::kInvalid:
2824 FATAL("unexpected case");
2825 return Handle<Object>::null();
2826 }
2827
2828 FATAL("internal error: value missing");
2829 return Handle<Object>::null();
2830}
2831
2832
2833void TranslatedValue::MaterializeSimple() {
2834 // If we already have materialized, return.
2835 if (!value_.is_null()) return;
2836
2837 Object* raw_value = GetRawValue();
2838 if (raw_value != isolate()->heap()->arguments_marker()) {
2839 // We can get the value without allocation, just return it here.
2840 value_ = Handle<Object>(raw_value, isolate());
2841 return;
2842 }
2843
2844 switch (kind()) {
2845 case kInt32: {
2846 value_ = Handle<Object>(isolate()->factory()->NewNumber(int32_value()));
2847 return;
2848 }
2849
2850 case kUInt32:
2851 value_ = Handle<Object>(isolate()->factory()->NewNumber(uint32_value()));
2852 return;
2853
2854 case kDouble:
2855 value_ = Handle<Object>(isolate()->factory()->NewNumber(double_value()));
2856 return;
2857
2858 case kCapturedObject:
2859 case kDuplicatedObject:
2860 case kArgumentsObject:
2861 case kInvalid:
2862 case kTagged:
2863 case kBoolBit:
2864 FATAL("internal error: unexpected materialization.");
2865 break;
2866 }
2867}
2868
2869
2870bool TranslatedValue::IsMaterializedObject() const {
2871 switch (kind()) {
2872 case kCapturedObject:
2873 case kDuplicatedObject:
2874 case kArgumentsObject:
2875 return true;
2876 default:
2877 return false;
2878 }
2879}
2880
Ben Murdoch097c5b22016-05-18 11:27:45 +01002881bool TranslatedValue::IsMaterializableByDebugger() const {
2882 // At the moment, we only allow materialization of doubles.
2883 return (kind() == kDouble);
2884}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002885
2886int TranslatedValue::GetChildrenCount() const {
2887 if (kind() == kCapturedObject || kind() == kArgumentsObject) {
2888 return object_length();
2889 } else {
2890 return 0;
2891 }
2892}
2893
2894
2895uint32_t TranslatedState::GetUInt32Slot(Address fp, int slot_offset) {
2896 Address address = fp + slot_offset;
2897#if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
2898 return Memory::uint32_at(address + kIntSize);
2899#else
2900 return Memory::uint32_at(address);
2901#endif
2902}
2903
2904
2905void TranslatedValue::Handlify() {
2906 if (kind() == kTagged) {
2907 value_ = Handle<Object>(raw_literal(), isolate());
2908 raw_literal_ = nullptr;
2909 }
2910}
2911
2912
2913TranslatedFrame TranslatedFrame::JSFrame(BailoutId node_id,
2914 SharedFunctionInfo* shared_info,
2915 int height) {
2916 TranslatedFrame frame(kFunction, shared_info->GetIsolate(), shared_info,
2917 height);
2918 frame.node_id_ = node_id;
2919 return frame;
2920}
2921
2922
2923TranslatedFrame TranslatedFrame::InterpretedFrame(
2924 BailoutId bytecode_offset, SharedFunctionInfo* shared_info, int height) {
2925 TranslatedFrame frame(kInterpretedFunction, shared_info->GetIsolate(),
2926 shared_info, height);
2927 frame.node_id_ = bytecode_offset;
2928 return frame;
2929}
2930
2931
2932TranslatedFrame TranslatedFrame::AccessorFrame(
2933 Kind kind, SharedFunctionInfo* shared_info) {
2934 DCHECK(kind == kSetter || kind == kGetter);
2935 return TranslatedFrame(kind, shared_info->GetIsolate(), shared_info);
2936}
2937
2938
2939TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame(
2940 SharedFunctionInfo* shared_info, int height) {
2941 return TranslatedFrame(kArgumentsAdaptor, shared_info->GetIsolate(),
2942 shared_info, height);
2943}
2944
2945
2946TranslatedFrame TranslatedFrame::ConstructStubFrame(
2947 SharedFunctionInfo* shared_info, int height) {
2948 return TranslatedFrame(kConstructStub, shared_info->GetIsolate(), shared_info,
2949 height);
2950}
2951
2952
2953int TranslatedFrame::GetValueCount() {
2954 switch (kind()) {
2955 case kFunction: {
2956 int parameter_count =
2957 raw_shared_info_->internal_formal_parameter_count() + 1;
2958 // + 1 for function.
2959 return height_ + parameter_count + 1;
2960 }
2961
2962 case kInterpretedFunction: {
2963 int parameter_count =
2964 raw_shared_info_->internal_formal_parameter_count() + 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002965 // + 2 for function and context.
2966 return height_ + parameter_count + 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002967 }
2968
2969 case kGetter:
2970 return 2; // Function and receiver.
2971
2972 case kSetter:
2973 return 3; // Function, receiver and the value to set.
2974
2975 case kArgumentsAdaptor:
2976 case kConstructStub:
2977 return 1 + height_;
2978
2979 case kCompiledStub:
2980 return height_;
2981
2982 case kInvalid:
2983 UNREACHABLE();
2984 break;
2985 }
2986 UNREACHABLE();
2987 return -1;
2988}
2989
2990
2991void TranslatedFrame::Handlify() {
2992 if (raw_shared_info_ != nullptr) {
2993 shared_info_ = Handle<SharedFunctionInfo>(raw_shared_info_);
2994 raw_shared_info_ = nullptr;
2995 }
2996 for (auto& value : values_) {
2997 value.Handlify();
2998 }
2999}
3000
3001
3002TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
3003 TranslationIterator* iterator, FixedArray* literal_array, Address fp,
3004 FILE* trace_file) {
3005 Translation::Opcode opcode =
3006 static_cast<Translation::Opcode>(iterator->Next());
3007 switch (opcode) {
3008 case Translation::JS_FRAME: {
3009 BailoutId node_id = BailoutId(iterator->Next());
3010 SharedFunctionInfo* shared_info =
3011 SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3012 int height = iterator->Next();
3013 if (trace_file != nullptr) {
3014 base::SmartArrayPointer<char> name =
3015 shared_info->DebugName()->ToCString();
3016 PrintF(trace_file, " reading input frame %s", name.get());
3017 int arg_count = shared_info->internal_formal_parameter_count() + 1;
3018 PrintF(trace_file, " => node=%d, args=%d, height=%d; inputs:\n",
3019 node_id.ToInt(), arg_count, height);
3020 }
3021 return TranslatedFrame::JSFrame(node_id, shared_info, height);
3022 }
3023
3024 case Translation::INTERPRETED_FRAME: {
3025 BailoutId bytecode_offset = BailoutId(iterator->Next());
3026 SharedFunctionInfo* shared_info =
3027 SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3028 int height = iterator->Next();
3029 if (trace_file != nullptr) {
3030 base::SmartArrayPointer<char> name =
3031 shared_info->DebugName()->ToCString();
3032 PrintF(trace_file, " reading input frame %s", name.get());
3033 int arg_count = shared_info->internal_formal_parameter_count() + 1;
3034 PrintF(trace_file,
3035 " => bytecode_offset=%d, args=%d, height=%d; inputs:\n",
3036 bytecode_offset.ToInt(), arg_count, height);
3037 }
3038 return TranslatedFrame::InterpretedFrame(bytecode_offset, shared_info,
3039 height);
3040 }
3041
3042 case Translation::ARGUMENTS_ADAPTOR_FRAME: {
3043 SharedFunctionInfo* shared_info =
3044 SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3045 int height = iterator->Next();
3046 if (trace_file != nullptr) {
3047 base::SmartArrayPointer<char> name =
3048 shared_info->DebugName()->ToCString();
3049 PrintF(trace_file, " reading arguments adaptor frame %s", name.get());
3050 PrintF(trace_file, " => height=%d; inputs:\n", height);
3051 }
3052 return TranslatedFrame::ArgumentsAdaptorFrame(shared_info, height);
3053 }
3054
3055 case Translation::CONSTRUCT_STUB_FRAME: {
3056 SharedFunctionInfo* shared_info =
3057 SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3058 int height = iterator->Next();
3059 if (trace_file != nullptr) {
3060 base::SmartArrayPointer<char> name =
3061 shared_info->DebugName()->ToCString();
3062 PrintF(trace_file, " reading construct stub frame %s", name.get());
3063 PrintF(trace_file, " => height=%d; inputs:\n", height);
3064 }
3065 return TranslatedFrame::ConstructStubFrame(shared_info, height);
3066 }
3067
3068 case Translation::GETTER_STUB_FRAME: {
3069 SharedFunctionInfo* shared_info =
3070 SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3071 if (trace_file != nullptr) {
3072 base::SmartArrayPointer<char> name =
3073 shared_info->DebugName()->ToCString();
3074 PrintF(trace_file, " reading getter frame %s; inputs:\n", name.get());
3075 }
3076 return TranslatedFrame::AccessorFrame(TranslatedFrame::kGetter,
3077 shared_info);
3078 }
3079
3080 case Translation::SETTER_STUB_FRAME: {
3081 SharedFunctionInfo* shared_info =
3082 SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3083 if (trace_file != nullptr) {
3084 base::SmartArrayPointer<char> name =
3085 shared_info->DebugName()->ToCString();
3086 PrintF(trace_file, " reading setter frame %s; inputs:\n", name.get());
3087 }
3088 return TranslatedFrame::AccessorFrame(TranslatedFrame::kSetter,
3089 shared_info);
3090 }
3091
3092 case Translation::COMPILED_STUB_FRAME: {
3093 int height = iterator->Next();
3094 if (trace_file != nullptr) {
3095 PrintF(trace_file,
3096 " reading compiler stub frame => height=%d; inputs:\n", height);
3097 }
3098 return TranslatedFrame::CompiledStubFrame(height,
3099 literal_array->GetIsolate());
3100 }
3101
3102 case Translation::BEGIN:
3103 case Translation::DUPLICATED_OBJECT:
3104 case Translation::ARGUMENTS_OBJECT:
3105 case Translation::CAPTURED_OBJECT:
3106 case Translation::REGISTER:
3107 case Translation::INT32_REGISTER:
3108 case Translation::UINT32_REGISTER:
3109 case Translation::BOOL_REGISTER:
3110 case Translation::DOUBLE_REGISTER:
3111 case Translation::STACK_SLOT:
3112 case Translation::INT32_STACK_SLOT:
3113 case Translation::UINT32_STACK_SLOT:
3114 case Translation::BOOL_STACK_SLOT:
3115 case Translation::DOUBLE_STACK_SLOT:
3116 case Translation::LITERAL:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003117 break;
3118 }
3119 FATAL("We should never get here - unexpected deopt info.");
3120 return TranslatedFrame::InvalidFrame();
3121}
3122
3123
3124// static
3125void TranslatedFrame::AdvanceIterator(
3126 std::deque<TranslatedValue>::iterator* iter) {
3127 int values_to_skip = 1;
3128 while (values_to_skip > 0) {
3129 // Consume the current element.
3130 values_to_skip--;
3131 // Add all the children.
3132 values_to_skip += (*iter)->GetChildrenCount();
3133
3134 (*iter)++;
3135 }
3136}
3137
3138
3139// We can't intermix stack decoding and allocations because
3140// deoptimization infrastracture is not GC safe.
3141// Thus we build a temporary structure in malloced space.
3142TranslatedValue TranslatedState::CreateNextTranslatedValue(
3143 int frame_index, int value_index, TranslationIterator* iterator,
3144 FixedArray* literal_array, Address fp, RegisterValues* registers,
3145 FILE* trace_file) {
3146 disasm::NameConverter converter;
3147
3148 Translation::Opcode opcode =
3149 static_cast<Translation::Opcode>(iterator->Next());
3150 switch (opcode) {
3151 case Translation::BEGIN:
3152 case Translation::JS_FRAME:
3153 case Translation::INTERPRETED_FRAME:
3154 case Translation::ARGUMENTS_ADAPTOR_FRAME:
3155 case Translation::CONSTRUCT_STUB_FRAME:
3156 case Translation::GETTER_STUB_FRAME:
3157 case Translation::SETTER_STUB_FRAME:
3158 case Translation::COMPILED_STUB_FRAME:
3159 // Peeled off before getting here.
3160 break;
3161
3162 case Translation::DUPLICATED_OBJECT: {
3163 int object_id = iterator->Next();
3164 if (trace_file != nullptr) {
3165 PrintF(trace_file, "duplicated object #%d", object_id);
3166 }
3167 object_positions_.push_back(object_positions_[object_id]);
3168 return TranslatedValue::NewDuplicateObject(this, object_id);
3169 }
3170
3171 case Translation::ARGUMENTS_OBJECT: {
3172 int arg_count = iterator->Next();
3173 int object_index = static_cast<int>(object_positions_.size());
3174 if (trace_file != nullptr) {
3175 PrintF(trace_file, "argumets object #%d (length = %d)", object_index,
3176 arg_count);
3177 }
3178 object_positions_.push_back({frame_index, value_index});
3179 return TranslatedValue::NewArgumentsObject(this, arg_count, object_index);
3180 }
3181
3182 case Translation::CAPTURED_OBJECT: {
3183 int field_count = iterator->Next();
3184 int object_index = static_cast<int>(object_positions_.size());
3185 if (trace_file != nullptr) {
3186 PrintF(trace_file, "captured object #%d (length = %d)", object_index,
3187 field_count);
3188 }
3189 object_positions_.push_back({frame_index, value_index});
3190 return TranslatedValue::NewDeferredObject(this, field_count,
3191 object_index);
3192 }
3193
3194 case Translation::REGISTER: {
3195 int input_reg = iterator->Next();
3196 if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3197 intptr_t value = registers->GetRegister(input_reg);
3198 if (trace_file != nullptr) {
3199 PrintF(trace_file, "0x%08" V8PRIxPTR " ; %s ", value,
3200 converter.NameOfCPURegister(input_reg));
3201 reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3202 }
3203 return TranslatedValue::NewTagged(this, reinterpret_cast<Object*>(value));
3204 }
3205
3206 case Translation::INT32_REGISTER: {
3207 int input_reg = iterator->Next();
3208 if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3209 intptr_t value = registers->GetRegister(input_reg);
3210 if (trace_file != nullptr) {
3211 PrintF(trace_file, "%" V8PRIdPTR " ; %s ", value,
3212 converter.NameOfCPURegister(input_reg));
3213 }
3214 return TranslatedValue::NewInt32(this, static_cast<int32_t>(value));
3215 }
3216
3217 case Translation::UINT32_REGISTER: {
3218 int input_reg = iterator->Next();
3219 if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3220 intptr_t value = registers->GetRegister(input_reg);
3221 if (trace_file != nullptr) {
3222 PrintF(trace_file, "%" V8PRIuPTR " ; %s (uint)", value,
3223 converter.NameOfCPURegister(input_reg));
3224 reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3225 }
3226 return TranslatedValue::NewUInt32(this, static_cast<uint32_t>(value));
3227 }
3228
3229 case Translation::BOOL_REGISTER: {
3230 int input_reg = iterator->Next();
3231 if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3232 intptr_t value = registers->GetRegister(input_reg);
3233 if (trace_file != nullptr) {
3234 PrintF(trace_file, "%" V8PRIdPTR " ; %s (bool)", value,
3235 converter.NameOfCPURegister(input_reg));
3236 }
3237 return TranslatedValue::NewBool(this, static_cast<uint32_t>(value));
3238 }
3239
3240 case Translation::DOUBLE_REGISTER: {
3241 int input_reg = iterator->Next();
3242 if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3243 double value = registers->GetDoubleRegister(input_reg);
3244 if (trace_file != nullptr) {
3245 PrintF(trace_file, "%e ; %s (bool)", value,
3246 DoubleRegister::from_code(input_reg).ToString());
3247 }
3248 return TranslatedValue::NewDouble(this, value);
3249 }
3250
3251 case Translation::STACK_SLOT: {
3252 int slot_offset =
3253 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3254 intptr_t value = *(reinterpret_cast<intptr_t*>(fp + slot_offset));
3255 if (trace_file != nullptr) {
3256 PrintF(trace_file, "0x%08" V8PRIxPTR " ; [fp %c %d] ", value,
3257 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3258 reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3259 }
3260 return TranslatedValue::NewTagged(this, reinterpret_cast<Object*>(value));
3261 }
3262
3263 case Translation::INT32_STACK_SLOT: {
3264 int slot_offset =
3265 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3266 uint32_t value = GetUInt32Slot(fp, slot_offset);
3267 if (trace_file != nullptr) {
3268 PrintF(trace_file, "%d ; (int) [fp %c %d] ",
3269 static_cast<int32_t>(value), slot_offset < 0 ? '-' : '+',
3270 std::abs(slot_offset));
3271 }
3272 return TranslatedValue::NewInt32(this, value);
3273 }
3274
3275 case Translation::UINT32_STACK_SLOT: {
3276 int slot_offset =
3277 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3278 uint32_t value = GetUInt32Slot(fp, slot_offset);
3279 if (trace_file != nullptr) {
3280 PrintF(trace_file, "%u ; (uint) [fp %c %d] ", value,
3281 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3282 }
3283 return TranslatedValue::NewUInt32(this, value);
3284 }
3285
3286 case Translation::BOOL_STACK_SLOT: {
3287 int slot_offset =
3288 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3289 uint32_t value = GetUInt32Slot(fp, slot_offset);
3290 if (trace_file != nullptr) {
3291 PrintF(trace_file, "%u ; (bool) [fp %c %d] ", value,
3292 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3293 }
3294 return TranslatedValue::NewBool(this, value);
3295 }
3296
3297 case Translation::DOUBLE_STACK_SLOT: {
3298 int slot_offset =
3299 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3300 double value = ReadDoubleValue(fp + slot_offset);
3301 if (trace_file != nullptr) {
3302 PrintF(trace_file, "%e ; (double) [fp %c %d] ", value,
3303 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3304 }
3305 return TranslatedValue::NewDouble(this, value);
3306 }
3307
3308 case Translation::LITERAL: {
3309 int literal_index = iterator->Next();
3310 Object* value = literal_array->get(literal_index);
3311 if (trace_file != nullptr) {
3312 PrintF(trace_file, "0x%08" V8PRIxPTR " ; (literal %d) ",
3313 reinterpret_cast<intptr_t>(value), literal_index);
3314 reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3315 }
3316
3317 return TranslatedValue::NewTagged(this, value);
3318 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003319 }
3320
3321 FATAL("We should never get here - unexpected deopt info.");
3322 return TranslatedValue(nullptr, TranslatedValue::kInvalid);
3323}
3324
3325
3326TranslatedState::TranslatedState(JavaScriptFrame* frame)
3327 : isolate_(nullptr),
3328 stack_frame_pointer_(nullptr),
3329 has_adapted_arguments_(false) {
3330 int deopt_index = Safepoint::kNoDeoptimizationIndex;
3331 DeoptimizationInputData* data =
3332 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
3333 TranslationIterator it(data->TranslationByteArray(),
3334 data->TranslationIndex(deopt_index)->value());
3335 Init(frame->fp(), &it, data->LiteralArray(), nullptr /* registers */,
3336 nullptr /* trace file */);
3337}
3338
3339
3340TranslatedState::TranslatedState()
3341 : isolate_(nullptr),
3342 stack_frame_pointer_(nullptr),
3343 has_adapted_arguments_(false) {}
3344
3345
3346void TranslatedState::Init(Address input_frame_pointer,
3347 TranslationIterator* iterator,
3348 FixedArray* literal_array, RegisterValues* registers,
3349 FILE* trace_file) {
3350 DCHECK(frames_.empty());
3351
3352 isolate_ = literal_array->GetIsolate();
3353 // Read out the 'header' translation.
3354 Translation::Opcode opcode =
3355 static_cast<Translation::Opcode>(iterator->Next());
3356 CHECK(opcode == Translation::BEGIN);
3357
3358 int count = iterator->Next();
3359 iterator->Next(); // Drop JS frames count.
3360
3361 frames_.reserve(count);
3362
3363 std::stack<int> nested_counts;
3364
3365 // Read the frames
3366 for (int i = 0; i < count; i++) {
3367 // Read the frame descriptor.
3368 frames_.push_back(CreateNextTranslatedFrame(
3369 iterator, literal_array, input_frame_pointer, trace_file));
3370 TranslatedFrame& frame = frames_.back();
3371
3372 // Read the values.
3373 int values_to_process = frame.GetValueCount();
3374 while (values_to_process > 0 || !nested_counts.empty()) {
3375 if (trace_file != nullptr) {
3376 if (nested_counts.empty()) {
3377 // For top level values, print the value number.
3378 PrintF(trace_file, " %3i: ",
3379 frame.GetValueCount() - values_to_process);
3380 } else {
3381 // Take care of indenting for nested values.
3382 PrintF(trace_file, " ");
3383 for (size_t j = 0; j < nested_counts.size(); j++) {
3384 PrintF(trace_file, " ");
3385 }
3386 }
3387 }
3388
3389 TranslatedValue value = CreateNextTranslatedValue(
3390 i, static_cast<int>(frame.values_.size()), iterator, literal_array,
3391 input_frame_pointer, registers, trace_file);
3392 frame.Add(value);
3393
3394 if (trace_file != nullptr) {
3395 PrintF(trace_file, "\n");
3396 }
3397
3398 // Update the value count and resolve the nesting.
3399 values_to_process--;
3400 int children_count = value.GetChildrenCount();
3401 if (children_count > 0) {
3402 nested_counts.push(values_to_process);
3403 values_to_process = children_count;
3404 } else {
3405 while (values_to_process == 0 && !nested_counts.empty()) {
3406 values_to_process = nested_counts.top();
3407 nested_counts.pop();
3408 }
3409 }
3410 }
3411 }
3412
3413 CHECK(!iterator->HasNext() ||
3414 static_cast<Translation::Opcode>(iterator->Next()) ==
3415 Translation::BEGIN);
3416}
3417
3418
3419void TranslatedState::Prepare(bool has_adapted_arguments,
3420 Address stack_frame_pointer) {
3421 for (auto& frame : frames_) frame.Handlify();
3422
3423 stack_frame_pointer_ = stack_frame_pointer;
3424 has_adapted_arguments_ = has_adapted_arguments;
3425
3426 UpdateFromPreviouslyMaterializedObjects();
3427}
3428
3429
3430Handle<Object> TranslatedState::MaterializeAt(int frame_index,
3431 int* value_index) {
3432 TranslatedFrame* frame = &(frames_[frame_index]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003433 CHECK(static_cast<size_t>(*value_index) < frame->values_.size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003434
3435 TranslatedValue* slot = &(frame->values_[*value_index]);
3436 (*value_index)++;
3437
3438 switch (slot->kind()) {
3439 case TranslatedValue::kTagged:
3440 case TranslatedValue::kInt32:
3441 case TranslatedValue::kUInt32:
3442 case TranslatedValue::kBoolBit:
3443 case TranslatedValue::kDouble: {
3444 slot->MaterializeSimple();
3445 Handle<Object> value = slot->GetValue();
3446 if (value->IsMutableHeapNumber()) {
3447 HeapNumber::cast(*value)->set_map(isolate()->heap()->heap_number_map());
3448 }
3449 return value;
3450 }
3451
3452 case TranslatedValue::kArgumentsObject: {
3453 int length = slot->GetChildrenCount();
3454 Handle<JSObject> arguments;
3455 if (GetAdaptedArguments(&arguments, frame_index)) {
3456 // Store the materialized object and consume the nested values.
3457 for (int i = 0; i < length; ++i) {
3458 MaterializeAt(frame_index, value_index);
3459 }
3460 } else {
3461 Handle<JSFunction> function =
3462 Handle<JSFunction>::cast(frame->front().GetValue());
3463 arguments = isolate_->factory()->NewArgumentsObject(function, length);
3464 Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
3465 DCHECK_EQ(array->length(), length);
3466 arguments->set_elements(*array);
3467 for (int i = 0; i < length; ++i) {
3468 Handle<Object> value = MaterializeAt(frame_index, value_index);
3469 array->set(i, *value);
3470 }
3471 }
3472 slot->value_ = arguments;
3473 return arguments;
3474 }
3475 case TranslatedValue::kCapturedObject: {
3476 int length = slot->GetChildrenCount();
3477
3478 // The map must be a tagged object.
3479 CHECK(frame->values_[*value_index].kind() == TranslatedValue::kTagged);
3480
3481 Handle<Object> result;
3482 if (slot->value_.ToHandle(&result)) {
3483 // This has been previously materialized, return the previous value.
3484 // We still need to skip all the nested objects.
3485 for (int i = 0; i < length; i++) {
3486 MaterializeAt(frame_index, value_index);
3487 }
3488
3489 return result;
3490 }
3491
3492 Handle<Object> map_object = MaterializeAt(frame_index, value_index);
3493 Handle<Map> map =
3494 Map::GeneralizeAllFieldRepresentations(Handle<Map>::cast(map_object));
3495 switch (map->instance_type()) {
3496 case MUTABLE_HEAP_NUMBER_TYPE:
3497 case HEAP_NUMBER_TYPE: {
3498 // Reuse the HeapNumber value directly as it is already properly
3499 // tagged and skip materializing the HeapNumber explicitly.
3500 Handle<Object> object = MaterializeAt(frame_index, value_index);
3501 slot->value_ = object;
3502 // On 32-bit architectures, there is an extra slot there because
3503 // the escape analysis calculates the number of slots as
3504 // object-size/pointer-size. To account for this, we read out
3505 // any extra slots.
3506 for (int i = 0; i < length - 2; i++) {
3507 MaterializeAt(frame_index, value_index);
3508 }
3509 return object;
3510 }
3511 case JS_OBJECT_TYPE: {
3512 Handle<JSObject> object =
3513 isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED);
3514 slot->value_ = object;
3515 Handle<Object> properties = MaterializeAt(frame_index, value_index);
3516 Handle<Object> elements = MaterializeAt(frame_index, value_index);
3517 object->set_properties(FixedArray::cast(*properties));
3518 object->set_elements(FixedArrayBase::cast(*elements));
3519 for (int i = 0; i < length - 3; ++i) {
3520 Handle<Object> value = MaterializeAt(frame_index, value_index);
3521 FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
3522 object->FastPropertyAtPut(index, *value);
3523 }
3524 return object;
3525 }
3526 case JS_ARRAY_TYPE: {
3527 Handle<JSArray> object =
3528 isolate_->factory()->NewJSArray(0, map->elements_kind());
3529 slot->value_ = object;
3530 Handle<Object> properties = MaterializeAt(frame_index, value_index);
3531 Handle<Object> elements = MaterializeAt(frame_index, value_index);
3532 Handle<Object> length = MaterializeAt(frame_index, value_index);
3533 object->set_properties(FixedArray::cast(*properties));
3534 object->set_elements(FixedArrayBase::cast(*elements));
3535 object->set_length(*length);
3536 return object;
3537 }
3538 case FIXED_ARRAY_TYPE: {
3539 Handle<Object> lengthObject = MaterializeAt(frame_index, value_index);
3540 int32_t length = 0;
3541 CHECK(lengthObject->ToInt32(&length));
3542 Handle<FixedArray> object =
3543 isolate_->factory()->NewFixedArray(length);
3544 // We need to set the map, because the fixed array we are
3545 // materializing could be a context or an arguments object,
3546 // in which case we must retain that information.
3547 object->set_map(*map);
3548 slot->value_ = object;
3549 for (int i = 0; i < length; ++i) {
3550 Handle<Object> value = MaterializeAt(frame_index, value_index);
3551 object->set(i, *value);
3552 }
3553 return object;
3554 }
3555 case FIXED_DOUBLE_ARRAY_TYPE: {
3556 DCHECK_EQ(*map, isolate_->heap()->fixed_double_array_map());
3557 Handle<Object> lengthObject = MaterializeAt(frame_index, value_index);
3558 int32_t length = 0;
3559 CHECK(lengthObject->ToInt32(&length));
3560 Handle<FixedArrayBase> object =
3561 isolate_->factory()->NewFixedDoubleArray(length);
3562 slot->value_ = object;
3563 if (length > 0) {
3564 Handle<FixedDoubleArray> double_array =
3565 Handle<FixedDoubleArray>::cast(object);
3566 for (int i = 0; i < length; ++i) {
3567 Handle<Object> value = MaterializeAt(frame_index, value_index);
3568 CHECK(value->IsNumber());
3569 double_array->set(i, value->Number());
3570 }
3571 }
3572 return object;
3573 }
3574 default:
3575 PrintF(stderr, "[couldn't handle instance type %d]\n",
3576 map->instance_type());
3577 FATAL("unreachable");
3578 return Handle<Object>::null();
3579 }
3580 UNREACHABLE();
3581 break;
3582 }
3583
3584 case TranslatedValue::kDuplicatedObject: {
3585 int object_index = slot->object_index();
3586 TranslatedState::ObjectPosition pos = object_positions_[object_index];
3587
3588 // Make sure the duplicate is refering to a previous object.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003589 CHECK(pos.frame_index_ < frame_index ||
3590 (pos.frame_index_ == frame_index &&
3591 pos.value_index_ < *value_index - 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003592
3593 Handle<Object> object =
3594 frames_[pos.frame_index_].values_[pos.value_index_].GetValue();
3595
3596 // The object should have a (non-sentinel) value.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003597 CHECK(!object.is_null() &&
3598 !object.is_identical_to(isolate_->factory()->arguments_marker()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003599
3600 slot->value_ = object;
3601 return object;
3602 }
3603
3604 case TranslatedValue::kInvalid:
3605 UNREACHABLE();
3606 break;
3607 }
3608
3609 FATAL("We should never get here - unexpected deopt slot kind.");
3610 return Handle<Object>::null();
3611}
3612
3613
3614Handle<Object> TranslatedState::MaterializeObjectAt(int object_index) {
3615 TranslatedState::ObjectPosition pos = object_positions_[object_index];
3616 return MaterializeAt(pos.frame_index_, &(pos.value_index_));
3617}
3618
3619
3620bool TranslatedState::GetAdaptedArguments(Handle<JSObject>* result,
3621 int frame_index) {
3622 if (frame_index == 0) {
3623 // Top level frame -> we need to go to the parent frame on the stack.
3624 if (!has_adapted_arguments_) return false;
3625
3626 // This is top level frame, so we need to go to the stack to get
3627 // this function's argument. (Note that this relies on not inlining
3628 // recursive functions!)
3629 Handle<JSFunction> function =
3630 Handle<JSFunction>::cast(frames_[frame_index].front().GetValue());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003631 *result = Accessors::FunctionGetArguments(function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003632 return true;
3633 } else {
3634 TranslatedFrame* previous_frame = &(frames_[frame_index]);
3635 if (previous_frame->kind() != TranslatedFrame::kArgumentsAdaptor) {
3636 return false;
3637 }
3638 // We get the adapted arguments from the parent translation.
3639 int length = previous_frame->height();
3640 Handle<JSFunction> function =
3641 Handle<JSFunction>::cast(previous_frame->front().GetValue());
3642 Handle<JSObject> arguments =
3643 isolate_->factory()->NewArgumentsObject(function, length);
3644 Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
3645 arguments->set_elements(*array);
3646 TranslatedFrame::iterator arg_iterator = previous_frame->begin();
3647 arg_iterator++; // Skip function.
3648 for (int i = 0; i < length; ++i) {
3649 Handle<Object> value = arg_iterator->GetValue();
3650 array->set(i, *value);
3651 arg_iterator++;
3652 }
3653 CHECK(arg_iterator == previous_frame->end());
3654 *result = arguments;
3655 return true;
3656 }
3657}
3658
3659
3660TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex(
3661 int jsframe_index, int* args_count) {
3662 for (size_t i = 0; i < frames_.size(); i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003663 if (frames_[i].kind() == TranslatedFrame::kFunction ||
3664 frames_[i].kind() == TranslatedFrame::kInterpretedFunction) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003665 if (jsframe_index > 0) {
3666 jsframe_index--;
3667 } else {
3668 // We have the JS function frame, now check if it has arguments adaptor.
3669 if (i > 0 &&
3670 frames_[i - 1].kind() == TranslatedFrame::kArgumentsAdaptor) {
3671 *args_count = frames_[i - 1].height();
3672 return &(frames_[i - 1]);
3673 }
3674 *args_count =
3675 frames_[i].shared_info()->internal_formal_parameter_count() + 1;
3676 return &(frames_[i]);
3677 }
3678 }
3679 }
3680 return nullptr;
3681}
3682
3683
3684void TranslatedState::StoreMaterializedValuesAndDeopt() {
3685 MaterializedObjectStore* materialized_store =
3686 isolate_->materialized_object_store();
3687 Handle<FixedArray> previously_materialized_objects =
3688 materialized_store->Get(stack_frame_pointer_);
3689
3690 Handle<Object> marker = isolate_->factory()->arguments_marker();
3691
3692 int length = static_cast<int>(object_positions_.size());
3693 bool new_store = false;
3694 if (previously_materialized_objects.is_null()) {
3695 previously_materialized_objects =
3696 isolate_->factory()->NewFixedArray(length);
3697 for (int i = 0; i < length; i++) {
3698 previously_materialized_objects->set(i, *marker);
3699 }
3700 new_store = true;
3701 }
3702
Ben Murdoch097c5b22016-05-18 11:27:45 +01003703 CHECK_EQ(length, previously_materialized_objects->length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003704
3705 bool value_changed = false;
3706 for (int i = 0; i < length; i++) {
3707 TranslatedState::ObjectPosition pos = object_positions_[i];
3708 TranslatedValue* value_info =
3709 &(frames_[pos.frame_index_].values_[pos.value_index_]);
3710
Ben Murdoch097c5b22016-05-18 11:27:45 +01003711 CHECK(value_info->IsMaterializedObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003712
3713 Handle<Object> value(value_info->GetRawValue(), isolate_);
3714
3715 if (!value.is_identical_to(marker)) {
3716 if (previously_materialized_objects->get(i) == *marker) {
3717 previously_materialized_objects->set(i, *value);
3718 value_changed = true;
3719 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003720 CHECK(previously_materialized_objects->get(i) == *value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003721 }
3722 }
3723 }
3724 if (new_store && value_changed) {
3725 materialized_store->Set(stack_frame_pointer_,
3726 previously_materialized_objects);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003727 CHECK(frames_[0].kind() == TranslatedFrame::kFunction ||
3728 frames_[0].kind() == TranslatedFrame::kInterpretedFunction);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003729 Object* const function = frames_[0].front().GetRawValue();
3730 Deoptimizer::DeoptimizeFunction(JSFunction::cast(function));
3731 }
3732}
3733
3734
3735void TranslatedState::UpdateFromPreviouslyMaterializedObjects() {
3736 MaterializedObjectStore* materialized_store =
3737 isolate_->materialized_object_store();
3738 Handle<FixedArray> previously_materialized_objects =
3739 materialized_store->Get(stack_frame_pointer_);
3740
3741 // If we have no previously materialized objects, there is nothing to do.
3742 if (previously_materialized_objects.is_null()) return;
3743
3744 Handle<Object> marker = isolate_->factory()->arguments_marker();
3745
3746 int length = static_cast<int>(object_positions_.size());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003747 CHECK_EQ(length, previously_materialized_objects->length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003748
3749 for (int i = 0; i < length; i++) {
3750 // For a previously materialized objects, inject their value into the
3751 // translated values.
3752 if (previously_materialized_objects->get(i) != *marker) {
3753 TranslatedState::ObjectPosition pos = object_positions_[i];
3754 TranslatedValue* value_info =
3755 &(frames_[pos.frame_index_].values_[pos.value_index_]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003756 CHECK(value_info->IsMaterializedObject());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003757
3758 value_info->value_ =
3759 Handle<Object>(previously_materialized_objects->get(i), isolate_);
3760 }
3761 }
3762}
3763
3764} // namespace internal
3765} // namespace v8