blob: e2e8a65e2eaf72d49f99b61d85c40837f13b75e2 [file] [log] [blame]
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "codegen.h"
31#include "deoptimizer.h"
32#include "disasm.h"
33#include "full-codegen.h"
34#include "global-handles.h"
35#include "macro-assembler.h"
36#include "prettyprinter.h"
37
38
39namespace v8 {
40namespace internal {
41
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042DeoptimizerData::DeoptimizerData() {
43 eager_deoptimization_entry_code_ = NULL;
44 lazy_deoptimization_entry_code_ = NULL;
45 current_ = NULL;
46 deoptimizing_code_list_ = NULL;
47}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048
49
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000050DeoptimizerData::~DeoptimizerData() {
51 if (eager_deoptimization_entry_code_ != NULL) {
52 eager_deoptimization_entry_code_->Free(EXECUTABLE);
53 eager_deoptimization_entry_code_ = NULL;
54 }
55 if (lazy_deoptimization_entry_code_ != NULL) {
56 lazy_deoptimization_entry_code_->Free(EXECUTABLE);
57 lazy_deoptimization_entry_code_ = NULL;
58 }
59}
60
kasperl@chromium.orga5551262010-12-07 12:49:48 +000061Deoptimizer* Deoptimizer::New(JSFunction* function,
62 BailoutType type,
63 unsigned bailout_id,
64 Address from,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 int fp_to_sp_delta,
66 Isolate* isolate) {
67 ASSERT(isolate == Isolate::Current());
68 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
69 function,
70 type,
71 bailout_id,
72 from,
73 fp_to_sp_delta);
74 ASSERT(isolate->deoptimizer_data()->current_ == NULL);
75 isolate->deoptimizer_data()->current_ = deoptimizer;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000076 return deoptimizer;
77}
78
79
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000080Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
81 ASSERT(isolate == Isolate::Current());
82 Deoptimizer* result = isolate->deoptimizer_data()->current_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000083 ASSERT(result != NULL);
84 result->DeleteFrameDescriptions();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000085 isolate->deoptimizer_data()->current_ = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000086 return result;
87}
88
89
90void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
91 int count,
92 BailoutType type) {
93 TableEntryGenerator generator(masm, type, count);
94 generator.Generate();
95}
96
97
98class DeoptimizingVisitor : public OptimizedFunctionVisitor {
99 public:
100 virtual void EnterContext(Context* context) {
101 if (FLAG_trace_deopt) {
102 PrintF("[deoptimize context: %" V8PRIxPTR "]\n",
103 reinterpret_cast<intptr_t>(context));
104 }
105 }
106
107 virtual void VisitFunction(JSFunction* function) {
108 Deoptimizer::DeoptimizeFunction(function);
109 }
110
111 virtual void LeaveContext(Context* context) {
112 context->ClearOptimizedFunctions();
113 }
114};
115
116
117void Deoptimizer::DeoptimizeAll() {
118 AssertNoAllocation no_allocation;
119
120 if (FLAG_trace_deopt) {
121 PrintF("[deoptimize all contexts]\n");
122 }
123
124 DeoptimizingVisitor visitor;
125 VisitAllOptimizedFunctions(&visitor);
126}
127
128
129void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
130 AssertNoAllocation no_allocation;
131
132 DeoptimizingVisitor visitor;
133 VisitAllOptimizedFunctionsForGlobalObject(object, &visitor);
134}
135
136
137void Deoptimizer::VisitAllOptimizedFunctionsForContext(
138 Context* context, OptimizedFunctionVisitor* visitor) {
139 AssertNoAllocation no_allocation;
140
141 ASSERT(context->IsGlobalContext());
142
143 visitor->EnterContext(context);
144 // Run through the list of optimized functions and deoptimize them.
145 Object* element = context->OptimizedFunctionsListHead();
146 while (!element->IsUndefined()) {
147 JSFunction* element_function = JSFunction::cast(element);
148 // Get the next link before deoptimizing as deoptimizing will clear the
149 // next link.
150 element = element_function->next_function_link();
151 visitor->VisitFunction(element_function);
152 }
153 visitor->LeaveContext(context);
154}
155
156
157void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject(
158 JSObject* object, OptimizedFunctionVisitor* visitor) {
159 AssertNoAllocation no_allocation;
160
161 if (object->IsJSGlobalProxy()) {
162 Object* proto = object->GetPrototype();
163 ASSERT(proto->IsJSGlobalObject());
164 VisitAllOptimizedFunctionsForContext(
165 GlobalObject::cast(proto)->global_context(), visitor);
166 } else if (object->IsGlobalObject()) {
167 VisitAllOptimizedFunctionsForContext(
168 GlobalObject::cast(object)->global_context(), visitor);
169 }
170}
171
172
173void Deoptimizer::VisitAllOptimizedFunctions(
174 OptimizedFunctionVisitor* visitor) {
175 AssertNoAllocation no_allocation;
176
177 // Run through the list of all global contexts and deoptimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 Object* global = Isolate::Current()->heap()->global_contexts_list();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000179 while (!global->IsUndefined()) {
180 VisitAllOptimizedFunctionsForGlobalObject(Context::cast(global)->global(),
181 visitor);
182 global = Context::cast(global)->get(Context::NEXT_CONTEXT_LINK);
183 }
184}
185
186
187void Deoptimizer::HandleWeakDeoptimizedCode(
188 v8::Persistent<v8::Value> obj, void* data) {
189 DeoptimizingCodeListNode* node =
190 reinterpret_cast<DeoptimizingCodeListNode*>(data);
191 RemoveDeoptimizingCode(*node->code());
192#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000194 while (node != NULL) {
195 ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
196 node = node->next();
197 }
198#endif
199}
200
201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000202void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000203 deoptimizer->DoComputeOutputFrames();
204}
205
206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000207Deoptimizer::Deoptimizer(Isolate* isolate,
208 JSFunction* function,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000209 BailoutType type,
210 unsigned bailout_id,
211 Address from,
212 int fp_to_sp_delta)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 : isolate_(isolate),
214 function_(function),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000215 bailout_id_(bailout_id),
216 bailout_type_(type),
217 from_(from),
218 fp_to_sp_delta_(fp_to_sp_delta),
219 output_count_(0),
220 output_(NULL),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000221 deferred_heap_numbers_(0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000222 if (FLAG_trace_deopt && type != OSR) {
223 PrintF("**** DEOPT: ");
224 function->PrintName();
225 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
226 bailout_id,
227 reinterpret_cast<intptr_t>(from),
228 fp_to_sp_delta - (2 * kPointerSize));
229 } else if (FLAG_trace_osr && type == OSR) {
230 PrintF("**** OSR: ");
231 function->PrintName();
232 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
233 bailout_id,
234 reinterpret_cast<intptr_t>(from),
235 fp_to_sp_delta - (2 * kPointerSize));
236 }
237 // Find the optimized code.
238 if (type == EAGER) {
239 ASSERT(from == NULL);
240 optimized_code_ = function_->code();
241 } else if (type == LAZY) {
242 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
243 ASSERT(optimized_code_ != NULL);
244 } else if (type == OSR) {
245 // The function has already been optimized and we're transitioning
246 // from the unoptimized shared version to the optimized one in the
247 // function. The return address (from) points to unoptimized code.
248 optimized_code_ = function_->code();
249 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
250 ASSERT(!optimized_code_->contains(from));
251 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000252 ASSERT(HEAP->allow_allocation(false));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000253 unsigned size = ComputeInputFrameSize();
254 input_ = new(size) FrameDescription(size, function);
255}
256
257
258Deoptimizer::~Deoptimizer() {
259 ASSERT(input_ == NULL && output_ == NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000260}
261
262
263void Deoptimizer::DeleteFrameDescriptions() {
264 delete input_;
265 for (int i = 0; i < output_count_; ++i) {
266 if (output_[i] != input_) delete output_[i];
267 }
268 delete[] output_;
269 input_ = NULL;
270 output_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 ASSERT(!HEAP->allow_allocation(true));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000272}
273
274
275Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
276 ASSERT(id >= 0);
277 if (id >= kNumberOfEntries) return NULL;
278 LargeObjectChunk* base = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000279 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000280 if (type == EAGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 if (data->eager_deoptimization_entry_code_ == NULL) {
282 data->eager_deoptimization_entry_code_ = CreateCode(type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000283 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 base = data->eager_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000285 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 if (data->lazy_deoptimization_entry_code_ == NULL) {
287 data->lazy_deoptimization_entry_code_ = CreateCode(type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000288 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 base = data->lazy_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000290 }
291 return
292 static_cast<Address>(base->GetStartAddress()) + (id * table_entry_size_);
293}
294
295
296int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
297 LargeObjectChunk* base = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000299 if (type == EAGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 base = data->eager_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000301 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 base = data->lazy_deoptimization_entry_code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000303 }
304 if (base == NULL ||
305 addr < base->GetStartAddress() ||
306 addr >= base->GetStartAddress() +
307 (kNumberOfEntries * table_entry_size_)) {
308 return kNotDeoptimizationEntry;
309 }
310 ASSERT_EQ(0,
311 static_cast<int>(addr - base->GetStartAddress()) % table_entry_size_);
312 return static_cast<int>(addr - base->GetStartAddress()) / table_entry_size_;
313}
314
315
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000316int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
317 unsigned id,
318 SharedFunctionInfo* shared) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000319 // TODO(kasperl): For now, we do a simple linear search for the PC
320 // offset associated with the given node id. This should probably be
321 // changed to a binary search.
322 int length = data->DeoptPoints();
323 Smi* smi_id = Smi::FromInt(id);
324 for (int i = 0; i < length; i++) {
325 if (data->AstId(i) == smi_id) {
326 return data->PcAndState(i)->value();
327 }
328 }
329 PrintF("[couldn't find pc offset for node=%u]\n", id);
330 PrintF("[method: %s]\n", *shared->DebugName()->ToCString());
331 // Print the source code if available.
332 HeapStringAllocator string_allocator;
333 StringStream stream(&string_allocator);
334 shared->SourceCodePrint(&stream, -1);
335 PrintF("[source:\n%s\n]", *stream.ToCString());
336
337 UNREACHABLE();
338 return -1;
339}
340
341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000342int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000343 int length = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 DeoptimizingCodeListNode* node =
345 isolate->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000346 while (node != NULL) {
347 length++;
348 node = node->next();
349 }
350 return length;
351}
352
353
354void Deoptimizer::DoComputeOutputFrames() {
355 if (bailout_type_ == OSR) {
356 DoComputeOsrOutputFrame();
357 return;
358 }
359
360 // Print some helpful diagnostic information.
361 int64_t start = OS::Ticks();
362 if (FLAG_trace_deopt) {
363 PrintF("[deoptimizing%s: begin 0x%08" V8PRIxPTR " ",
364 (bailout_type_ == LAZY ? " (lazy)" : ""),
365 reinterpret_cast<intptr_t>(function_));
366 function_->PrintName();
367 PrintF(" @%d]\n", bailout_id_);
368 }
369
370 // Determine basic deoptimization information. The optimized frame is
371 // described by the input data.
372 DeoptimizationInputData* input_data =
373 DeoptimizationInputData::cast(optimized_code_->deoptimization_data());
374 unsigned node_id = input_data->AstId(bailout_id_)->value();
375 ByteArray* translations = input_data->TranslationByteArray();
376 unsigned translation_index =
377 input_data->TranslationIndex(bailout_id_)->value();
378
379 // Do the input frame to output frame(s) translation.
380 TranslationIterator iterator(translations, translation_index);
381 Translation::Opcode opcode =
382 static_cast<Translation::Opcode>(iterator.Next());
383 ASSERT(Translation::BEGIN == opcode);
384 USE(opcode);
385 // Read the number of output frames and allocate an array for their
386 // descriptions.
387 int count = iterator.Next();
388 ASSERT(output_ == NULL);
389 output_ = new FrameDescription*[count];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000390 for (int i = 0; i < count; ++i) {
391 output_[i] = NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000392 }
393 output_count_ = count;
394
395 // Translate each output frame.
396 for (int i = 0; i < count; ++i) {
397 DoComputeFrame(&iterator, i);
398 }
399
400 // Print some helpful diagnostic information.
401 if (FLAG_trace_deopt) {
402 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
403 int index = output_count_ - 1; // Index of the topmost frame.
404 JSFunction* function = output_[index]->GetFunction();
405 PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
406 reinterpret_cast<intptr_t>(function));
407 function->PrintName();
408 PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
409 node_id,
410 output_[index]->GetPc(),
411 FullCodeGenerator::State2String(
412 static_cast<FullCodeGenerator::State>(
413 output_[index]->GetState()->value())),
414 ms);
415 }
416}
417
418
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000419void Deoptimizer::MaterializeHeapNumbers() {
420 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
421 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
422 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
423 if (FLAG_trace_deopt) {
424 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
425 reinterpret_cast<void*>(*num),
426 d.value(),
427 d.slot_address());
428 }
429
430 Memory::Object_at(d.slot_address()) = *num;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000431 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000432}
433
434
435void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
436 int frame_index,
437 unsigned output_offset) {
438 disasm::NameConverter converter;
439 // A GC-safe temporary placeholder that we can put in the output frame.
440 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
441
442 // Ignore commands marked as duplicate and act on the first non-duplicate.
443 Translation::Opcode opcode =
444 static_cast<Translation::Opcode>(iterator->Next());
445 while (opcode == Translation::DUPLICATE) {
446 opcode = static_cast<Translation::Opcode>(iterator->Next());
447 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
448 opcode = static_cast<Translation::Opcode>(iterator->Next());
449 }
450
451 switch (opcode) {
452 case Translation::BEGIN:
453 case Translation::FRAME:
454 case Translation::DUPLICATE:
455 UNREACHABLE();
456 return;
457
458 case Translation::REGISTER: {
459 int input_reg = iterator->Next();
460 intptr_t input_value = input_->GetRegister(input_reg);
461 if (FLAG_trace_deopt) {
462 PrintF(
463 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s\n",
464 output_[frame_index]->GetTop() + output_offset,
465 output_offset,
466 input_value,
467 converter.NameOfCPURegister(input_reg));
468 }
469 output_[frame_index]->SetFrameSlot(output_offset, input_value);
470 return;
471 }
472
473 case Translation::INT32_REGISTER: {
474 int input_reg = iterator->Next();
475 intptr_t value = input_->GetRegister(input_reg);
476 bool is_smi = Smi::IsValid(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000477 if (FLAG_trace_deopt) {
478 PrintF(
479 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
480 output_[frame_index]->GetTop() + output_offset,
481 output_offset,
482 value,
483 converter.NameOfCPURegister(input_reg),
484 is_smi ? "smi" : "heap number");
485 }
486 if (is_smi) {
487 intptr_t tagged_value =
488 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
489 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
490 } else {
491 // We save the untagged value on the side and store a GC-safe
492 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000493 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
494 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000495 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
496 }
497 return;
498 }
499
500 case Translation::DOUBLE_REGISTER: {
501 int input_reg = iterator->Next();
502 double value = input_->GetDoubleRegister(input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000503 if (FLAG_trace_deopt) {
504 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
505 output_[frame_index]->GetTop() + output_offset,
506 output_offset,
507 value,
508 DoubleRegister::AllocationIndexToString(input_reg));
509 }
510 // We save the untagged value on the side and store a GC-safe
511 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000512 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000513 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
514 return;
515 }
516
517 case Translation::STACK_SLOT: {
518 int input_slot_index = iterator->Next();
519 unsigned input_offset =
520 input_->GetOffsetFromSlotIndex(this, input_slot_index);
521 intptr_t input_value = input_->GetFrameSlot(input_offset);
522 if (FLAG_trace_deopt) {
523 PrintF(" 0x%08" V8PRIxPTR ": ",
524 output_[frame_index]->GetTop() + output_offset);
525 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d]\n",
526 output_offset,
527 input_value,
528 input_offset);
529 }
530 output_[frame_index]->SetFrameSlot(output_offset, input_value);
531 return;
532 }
533
534 case Translation::INT32_STACK_SLOT: {
535 int input_slot_index = iterator->Next();
536 unsigned input_offset =
537 input_->GetOffsetFromSlotIndex(this, input_slot_index);
538 intptr_t value = input_->GetFrameSlot(input_offset);
539 bool is_smi = Smi::IsValid(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000540 if (FLAG_trace_deopt) {
541 PrintF(" 0x%08" V8PRIxPTR ": ",
542 output_[frame_index]->GetTop() + output_offset);
543 PrintF("[top + %d] <- %" V8PRIdPTR " ; [esp + %d] (%s)\n",
544 output_offset,
545 value,
546 input_offset,
547 is_smi ? "smi" : "heap number");
548 }
549 if (is_smi) {
550 intptr_t tagged_value =
551 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
552 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
553 } else {
554 // We save the untagged value on the side and store a GC-safe
555 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000556 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
557 static_cast<double>(static_cast<int32_t>(value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000558 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
559 }
560 return;
561 }
562
563 case Translation::DOUBLE_STACK_SLOT: {
564 int input_slot_index = iterator->Next();
565 unsigned input_offset =
566 input_->GetOffsetFromSlotIndex(this, input_slot_index);
567 double value = input_->GetDoubleFrameSlot(input_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000568 if (FLAG_trace_deopt) {
569 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
570 output_[frame_index]->GetTop() + output_offset,
571 output_offset,
572 value,
573 input_offset);
574 }
575 // We save the untagged value on the side and store a GC-safe
576 // temporary placeholder in the frame.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000577 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000578 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
579 return;
580 }
581
582 case Translation::LITERAL: {
583 Object* literal = ComputeLiteral(iterator->Next());
584 if (FLAG_trace_deopt) {
585 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
586 output_[frame_index]->GetTop() + output_offset,
587 output_offset);
588 literal->ShortPrint();
589 PrintF(" ; literal\n");
590 }
591 intptr_t value = reinterpret_cast<intptr_t>(literal);
592 output_[frame_index]->SetFrameSlot(output_offset, value);
593 return;
594 }
595
596 case Translation::ARGUMENTS_OBJECT: {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000597 // Use the arguments marker value as a sentinel and fill in the arguments
598 // object after the deoptimized frame is built.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 ASSERT(frame_index == 0); // Only supported for first frame.
600 if (FLAG_trace_deopt) {
601 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
602 output_[frame_index]->GetTop() + output_offset,
603 output_offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 isolate_->heap()->arguments_marker()->ShortPrint();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000605 PrintF(" ; arguments object\n");
606 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 intptr_t value = reinterpret_cast<intptr_t>(
608 isolate_->heap()->arguments_marker());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000609 output_[frame_index]->SetFrameSlot(output_offset, value);
610 return;
611 }
612 }
613}
614
615
616bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
617 int* input_offset) {
618 disasm::NameConverter converter;
619 FrameDescription* output = output_[0];
620
621 // The input values are all part of the unoptimized frame so they
622 // are all tagged pointers.
623 uintptr_t input_value = input_->GetFrameSlot(*input_offset);
624 Object* input_object = reinterpret_cast<Object*>(input_value);
625
626 Translation::Opcode opcode =
627 static_cast<Translation::Opcode>(iterator->Next());
628 bool duplicate = (opcode == Translation::DUPLICATE);
629 if (duplicate) {
630 opcode = static_cast<Translation::Opcode>(iterator->Next());
631 }
632
633 switch (opcode) {
634 case Translation::BEGIN:
635 case Translation::FRAME:
636 case Translation::DUPLICATE:
637 UNREACHABLE(); // Malformed input.
638 return false;
639
640 case Translation::REGISTER: {
641 int output_reg = iterator->Next();
642 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000643 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000644 converter.NameOfCPURegister(output_reg),
645 input_value,
646 *input_offset);
647 }
648 output->SetRegister(output_reg, input_value);
649 break;
650 }
651
652 case Translation::INT32_REGISTER: {
653 // Abort OSR if we don't have a number.
654 if (!input_object->IsNumber()) return false;
655
656 int output_reg = iterator->Next();
657 int int32_value = input_object->IsSmi()
658 ? Smi::cast(input_object)->value()
659 : FastD2I(input_object->Number());
660 // Abort the translation if the conversion lost information.
661 if (!input_object->IsSmi() &&
662 FastI2D(int32_value) != input_object->Number()) {
663 if (FLAG_trace_osr) {
664 PrintF("**** %g could not be converted to int32 ****\n",
665 input_object->Number());
666 }
667 return false;
668 }
669 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000670 PrintF(" %s <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000671 converter.NameOfCPURegister(output_reg),
672 int32_value,
673 *input_offset);
674 }
675 output->SetRegister(output_reg, int32_value);
676 break;
677 }
678
679 case Translation::DOUBLE_REGISTER: {
680 // Abort OSR if we don't have a number.
681 if (!input_object->IsNumber()) return false;
682
683 int output_reg = iterator->Next();
684 double double_value = input_object->Number();
685 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000686 PrintF(" %s <- %g (double) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000687 DoubleRegister::AllocationIndexToString(output_reg),
688 double_value,
689 *input_offset);
690 }
691 output->SetDoubleRegister(output_reg, double_value);
692 break;
693 }
694
695 case Translation::STACK_SLOT: {
696 int output_index = iterator->Next();
697 unsigned output_offset =
698 output->GetOffsetFromSlotIndex(this, output_index);
699 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000700 PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000701 output_offset,
702 input_value,
703 *input_offset);
704 }
705 output->SetFrameSlot(output_offset, input_value);
706 break;
707 }
708
709 case Translation::INT32_STACK_SLOT: {
710 // Abort OSR if we don't have a number.
711 if (!input_object->IsNumber()) return false;
712
713 int output_index = iterator->Next();
714 unsigned output_offset =
715 output->GetOffsetFromSlotIndex(this, output_index);
716 int int32_value = input_object->IsSmi()
717 ? Smi::cast(input_object)->value()
718 : DoubleToInt32(input_object->Number());
719 // Abort the translation if the conversion lost information.
720 if (!input_object->IsSmi() &&
721 FastI2D(int32_value) != input_object->Number()) {
722 if (FLAG_trace_osr) {
723 PrintF("**** %g could not be converted to int32 ****\n",
724 input_object->Number());
725 }
726 return false;
727 }
728 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000729 PrintF(" [sp + %d] <- %d (int32) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000730 output_offset,
731 int32_value,
732 *input_offset);
733 }
734 output->SetFrameSlot(output_offset, int32_value);
735 break;
736 }
737
738 case Translation::DOUBLE_STACK_SLOT: {
739 static const int kLowerOffset = 0 * kPointerSize;
740 static const int kUpperOffset = 1 * kPointerSize;
741
742 // Abort OSR if we don't have a number.
743 if (!input_object->IsNumber()) return false;
744
745 int output_index = iterator->Next();
746 unsigned output_offset =
747 output->GetOffsetFromSlotIndex(this, output_index);
748 double double_value = input_object->Number();
749 uint64_t int_value = BitCast<uint64_t, double>(double_value);
750 int32_t lower = static_cast<int32_t>(int_value);
751 int32_t upper = static_cast<int32_t>(int_value >> kBitsPerInt);
752 if (FLAG_trace_osr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000753 PrintF(" [sp + %d] <- 0x%08x (upper bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000754 output_offset + kUpperOffset,
755 upper,
756 double_value,
757 *input_offset);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000758 PrintF(" [sp + %d] <- 0x%08x (lower bits of %g) ; [sp + %d]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000759 output_offset + kLowerOffset,
760 lower,
761 double_value,
762 *input_offset);
763 }
764 output->SetFrameSlot(output_offset + kLowerOffset, lower);
765 output->SetFrameSlot(output_offset + kUpperOffset, upper);
766 break;
767 }
768
769 case Translation::LITERAL: {
770 // Just ignore non-materialized literals.
771 iterator->Next();
772 break;
773 }
774
775 case Translation::ARGUMENTS_OBJECT: {
776 // Optimized code assumes that the argument object has not been
777 // materialized and so bypasses it when doing arguments access.
778 // We should have bailed out before starting the frame
779 // translation.
780 UNREACHABLE();
781 return false;
782 }
783 }
784
785 if (!duplicate) *input_offset -= kPointerSize;
786 return true;
787}
788
789
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000790void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
791 Code* check_code,
792 Code* replacement_code) {
793 // Iterate over the stack check table and patch every stack check
794 // call to an unconditional call to the replacement code.
795 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
796 Address stack_check_cursor = unoptimized_code->instruction_start() +
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000797 unoptimized_code->stack_check_table_offset();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000798 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
799 stack_check_cursor += kIntSize;
800 for (uint32_t i = 0; i < table_length; ++i) {
801 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
802 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
803 PatchStackCheckCodeAt(pc_after, check_code, replacement_code);
804 stack_check_cursor += 2 * kIntSize;
805 }
806}
807
808
809void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
810 Code* check_code,
811 Code* replacement_code) {
812 // Iterate over the stack check table and revert the patched
813 // stack check calls.
814 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
815 Address stack_check_cursor = unoptimized_code->instruction_start() +
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000816 unoptimized_code->stack_check_table_offset();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000817 uint32_t table_length = Memory::uint32_at(stack_check_cursor);
818 stack_check_cursor += kIntSize;
819 for (uint32_t i = 0; i < table_length; ++i) {
820 uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
821 Address pc_after = unoptimized_code->instruction_start() + pc_offset;
822 RevertStackCheckCodeAt(pc_after, check_code, replacement_code);
823 stack_check_cursor += 2 * kIntSize;
824 }
825}
826
827
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000828unsigned Deoptimizer::ComputeInputFrameSize() const {
829 unsigned fixed_size = ComputeFixedSize(function_);
830 // The fp-to-sp delta already takes the context and the function
831 // into account so we have to avoid double counting them (-2).
832 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize);
833#ifdef DEBUG
834 if (bailout_type_ == OSR) {
835 // TODO(kasperl): It would be nice if we could verify that the
836 // size matches with the stack height we can compute based on the
837 // environment at the OSR entry. The code for that his built into
838 // the DoComputeOsrOutputFrame function for now.
839 } else {
840 unsigned stack_slots = optimized_code_->stack_slots();
841 unsigned outgoing_size = ComputeOutgoingArgumentSize();
842 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
843 }
844#endif
845 return result;
846}
847
848
849unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
850 // The fixed part of the frame consists of the return address, frame
851 // pointer, function, context, and all the incoming arguments.
852 static const unsigned kFixedSlotSize = 4 * kPointerSize;
853 return ComputeIncomingArgumentSize(function) + kFixedSlotSize;
854}
855
856
857unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
858 // The incoming arguments is the values for formal parameters and
859 // the receiver. Every slot contains a pointer.
860 unsigned arguments = function->shared()->formal_parameter_count() + 1;
861 return arguments * kPointerSize;
862}
863
864
865unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
866 DeoptimizationInputData* data = DeoptimizationInputData::cast(
867 optimized_code_->deoptimization_data());
868 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
869 return height * kPointerSize;
870}
871
872
873Object* Deoptimizer::ComputeLiteral(int index) const {
874 DeoptimizationInputData* data = DeoptimizationInputData::cast(
875 optimized_code_->deoptimization_data());
876 FixedArray* literals = data->LiteralArray();
877 return literals->get(index);
878}
879
880
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000881void Deoptimizer::AddDoubleValue(intptr_t slot_address,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000882 double value) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000883 HeapNumberMaterializationDescriptor value_desc(
884 reinterpret_cast<Address>(slot_address), value);
885 deferred_heap_numbers_.Add(value_desc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000886}
887
888
889LargeObjectChunk* Deoptimizer::CreateCode(BailoutType type) {
890 // We cannot run this if the serializer is enabled because this will
891 // cause us to emit relocation information for the external
892 // references. This is fine because the deoptimizer's code section
893 // isn't meant to be serialized at all.
894 ASSERT(!Serializer::enabled());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000896 MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000897 masm.set_emit_debug_code(false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000898 GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
899 CodeDesc desc;
900 masm.GetCode(&desc);
901 ASSERT(desc.reloc_size == 0);
902
903 LargeObjectChunk* chunk = LargeObjectChunk::New(desc.instr_size, EXECUTABLE);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000904 if (chunk == NULL) {
905 V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
906 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000907 memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size);
908 CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000909 return chunk;
910}
911
912
913Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000914 DeoptimizingCodeListNode* node =
915 Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000916 while (node != NULL) {
917 if (node->code()->contains(addr)) return *node->code();
918 node = node->next();
919 }
920 return NULL;
921}
922
923
924void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
926 ASSERT(data->deoptimizing_code_list_ != NULL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000927 // Run through the code objects to find this one and remove it.
928 DeoptimizingCodeListNode* prev = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000930 while (current != NULL) {
931 if (*current->code() == code) {
932 // Unlink from list. If prev is NULL we are looking at the first element.
933 if (prev == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 data->deoptimizing_code_list_ = current->next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000935 } else {
936 prev->set_next(current->next());
937 }
938 delete current;
939 return;
940 }
941 // Move to next in list.
942 prev = current;
943 current = current->next();
944 }
945 // Deoptimizing code is removed through weak callback. Each object is expected
946 // to be removed once and only once.
947 UNREACHABLE();
948}
949
950
951FrameDescription::FrameDescription(uint32_t frame_size,
952 JSFunction* function)
953 : frame_size_(frame_size),
954 function_(function),
955 top_(kZapUint32),
956 pc_(kZapUint32),
957 fp_(kZapUint32) {
958 // Zap all the registers.
959 for (int r = 0; r < Register::kNumRegisters; r++) {
960 SetRegister(r, kZapUint32);
961 }
962
963 // Zap all the slots.
964 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
965 SetFrameSlot(o, kZapUint32);
966 }
967}
968
969
970unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer,
971 int slot_index) {
972 if (slot_index >= 0) {
973 // Local or spill slots. Skip the fixed part of the frame
974 // including all arguments.
975 unsigned base = static_cast<unsigned>(
976 GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()));
977 return base - ((slot_index + 1) * kPointerSize);
978 } else {
979 // Incoming parameter.
980 unsigned base = static_cast<unsigned>(GetFrameSize() -
981 deoptimizer->ComputeIncomingArgumentSize(GetFunction()));
982 return base - ((slot_index + 1) * kPointerSize);
983 }
984}
985
986
987void TranslationBuffer::Add(int32_t value) {
988 // Encode the sign bit in the least significant bit.
989 bool is_negative = (value < 0);
990 uint32_t bits = ((is_negative ? -value : value) << 1) |
991 static_cast<int32_t>(is_negative);
992 // Encode the individual bytes using the least significant bit of
993 // each byte to indicate whether or not more bytes follow.
994 do {
995 uint32_t next = bits >> 7;
996 contents_.Add(((bits << 1) & 0xFF) | (next != 0));
997 bits = next;
998 } while (bits != 0);
999}
1000
1001
1002int32_t TranslationIterator::Next() {
1003 ASSERT(HasNext());
1004 // Run through the bytes until we reach one with a least significant
1005 // bit of zero (marks the end).
1006 uint32_t bits = 0;
1007 for (int i = 0; true; i += 7) {
1008 uint8_t next = buffer_->get(index_++);
1009 bits |= (next >> 1) << i;
1010 if ((next & 1) == 0) break;
1011 }
1012 // The bits encode the sign in the least significant bit.
1013 bool is_negative = (bits & 1) == 1;
1014 int32_t result = bits >> 1;
1015 return is_negative ? -result : result;
1016}
1017
1018
1019Handle<ByteArray> TranslationBuffer::CreateByteArray() {
1020 int length = contents_.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 Handle<ByteArray> result =
1022 Isolate::Current()->factory()->NewByteArray(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001023 memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
1024 return result;
1025}
1026
1027
1028void Translation::BeginFrame(int node_id, int literal_id, unsigned height) {
1029 buffer_->Add(FRAME);
1030 buffer_->Add(node_id);
1031 buffer_->Add(literal_id);
1032 buffer_->Add(height);
1033}
1034
1035
1036void Translation::StoreRegister(Register reg) {
1037 buffer_->Add(REGISTER);
1038 buffer_->Add(reg.code());
1039}
1040
1041
1042void Translation::StoreInt32Register(Register reg) {
1043 buffer_->Add(INT32_REGISTER);
1044 buffer_->Add(reg.code());
1045}
1046
1047
1048void Translation::StoreDoubleRegister(DoubleRegister reg) {
1049 buffer_->Add(DOUBLE_REGISTER);
1050 buffer_->Add(DoubleRegister::ToAllocationIndex(reg));
1051}
1052
1053
1054void Translation::StoreStackSlot(int index) {
1055 buffer_->Add(STACK_SLOT);
1056 buffer_->Add(index);
1057}
1058
1059
1060void Translation::StoreInt32StackSlot(int index) {
1061 buffer_->Add(INT32_STACK_SLOT);
1062 buffer_->Add(index);
1063}
1064
1065
1066void Translation::StoreDoubleStackSlot(int index) {
1067 buffer_->Add(DOUBLE_STACK_SLOT);
1068 buffer_->Add(index);
1069}
1070
1071
1072void Translation::StoreLiteral(int literal_id) {
1073 buffer_->Add(LITERAL);
1074 buffer_->Add(literal_id);
1075}
1076
1077
1078void Translation::StoreArgumentsObject() {
1079 buffer_->Add(ARGUMENTS_OBJECT);
1080}
1081
1082
1083void Translation::MarkDuplicate() {
1084 buffer_->Add(DUPLICATE);
1085}
1086
1087
1088int Translation::NumberOfOperandsFor(Opcode opcode) {
1089 switch (opcode) {
1090 case ARGUMENTS_OBJECT:
1091 case DUPLICATE:
1092 return 0;
1093 case BEGIN:
1094 case REGISTER:
1095 case INT32_REGISTER:
1096 case DOUBLE_REGISTER:
1097 case STACK_SLOT:
1098 case INT32_STACK_SLOT:
1099 case DOUBLE_STACK_SLOT:
1100 case LITERAL:
1101 return 1;
1102 case FRAME:
1103 return 3;
1104 }
1105 UNREACHABLE();
1106 return -1;
1107}
1108
1109
whesse@chromium.org7b260152011-06-20 15:33:18 +00001110#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001111
1112const char* Translation::StringFor(Opcode opcode) {
1113 switch (opcode) {
1114 case BEGIN:
1115 return "BEGIN";
1116 case FRAME:
1117 return "FRAME";
1118 case REGISTER:
1119 return "REGISTER";
1120 case INT32_REGISTER:
1121 return "INT32_REGISTER";
1122 case DOUBLE_REGISTER:
1123 return "DOUBLE_REGISTER";
1124 case STACK_SLOT:
1125 return "STACK_SLOT";
1126 case INT32_STACK_SLOT:
1127 return "INT32_STACK_SLOT";
1128 case DOUBLE_STACK_SLOT:
1129 return "DOUBLE_STACK_SLOT";
1130 case LITERAL:
1131 return "LITERAL";
1132 case ARGUMENTS_OBJECT:
1133 return "ARGUMENTS_OBJECT";
1134 case DUPLICATE:
1135 return "DUPLICATE";
1136 }
1137 UNREACHABLE();
1138 return "";
1139}
1140
1141#endif
1142
1143
1144DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 GlobalHandles* global_handles = Isolate::Current()->global_handles();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001146 // Globalize the code object and make it weak.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 code_ = Handle<Code>::cast(global_handles->Create(code));
1148 global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
1149 this,
1150 Deoptimizer::HandleWeakDeoptimizedCode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001151}
1152
1153
1154DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001155 GlobalHandles* global_handles = Isolate::Current()->global_handles();
1156 global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001157}
1158
1159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001160// We can't intermix stack decoding and allocations because
1161// deoptimization infrastracture is not GC safe.
1162// Thus we build a temporary structure in malloced space.
1163SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
1164 DeoptimizationInputData* data,
1165 JavaScriptFrame* frame) {
1166 Translation::Opcode opcode =
1167 static_cast<Translation::Opcode>(iterator->Next());
1168
1169 switch (opcode) {
1170 case Translation::BEGIN:
1171 case Translation::FRAME:
1172 // Peeled off before getting here.
1173 break;
1174
1175 case Translation::ARGUMENTS_OBJECT:
1176 // This can be only emitted for local slots not for argument slots.
1177 break;
1178
1179 case Translation::REGISTER:
1180 case Translation::INT32_REGISTER:
1181 case Translation::DOUBLE_REGISTER:
1182 case Translation::DUPLICATE:
1183 // We are at safepoint which corresponds to call. All registers are
1184 // saved by caller so there would be no live registers at this
1185 // point. Thus these translation commands should not be used.
1186 break;
1187
1188 case Translation::STACK_SLOT: {
1189 int slot_index = iterator->Next();
1190 Address slot_addr = SlotAddress(frame, slot_index);
1191 return SlotRef(slot_addr, SlotRef::TAGGED);
1192 }
1193
1194 case Translation::INT32_STACK_SLOT: {
1195 int slot_index = iterator->Next();
1196 Address slot_addr = SlotAddress(frame, slot_index);
1197 return SlotRef(slot_addr, SlotRef::INT32);
1198 }
1199
1200 case Translation::DOUBLE_STACK_SLOT: {
1201 int slot_index = iterator->Next();
1202 Address slot_addr = SlotAddress(frame, slot_index);
1203 return SlotRef(slot_addr, SlotRef::DOUBLE);
1204 }
1205
1206 case Translation::LITERAL: {
1207 int literal_index = iterator->Next();
1208 return SlotRef(data->LiteralArray()->get(literal_index));
1209 }
1210 }
1211
1212 UNREACHABLE();
1213 return SlotRef();
1214}
1215
1216
1217void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame,
1218 int inlined_frame_index,
1219 Vector<SlotRef>* args_slots) {
1220 AssertNoAllocation no_gc;
1221 int deopt_index = AstNode::kNoNumber;
1222 DeoptimizationInputData* data =
1223 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
1224 TranslationIterator it(data->TranslationByteArray(),
1225 data->TranslationIndex(deopt_index)->value());
1226 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1227 ASSERT(opcode == Translation::BEGIN);
1228 int frame_count = it.Next();
1229 USE(frame_count);
1230 ASSERT(frame_count > inlined_frame_index);
1231 int frames_to_skip = inlined_frame_index;
1232 while (true) {
1233 opcode = static_cast<Translation::Opcode>(it.Next());
1234 // Skip over operands to advance to the next opcode.
1235 it.Skip(Translation::NumberOfOperandsFor(opcode));
1236 if (opcode == Translation::FRAME) {
1237 if (frames_to_skip == 0) {
1238 // We reached the frame corresponding to the inlined function
1239 // in question. Process the translation commands for the
1240 // arguments.
1241 //
1242 // Skip the translation command for the receiver.
1243 it.Skip(Translation::NumberOfOperandsFor(
1244 static_cast<Translation::Opcode>(it.Next())));
1245 // Compute slots for arguments.
1246 for (int i = 0; i < args_slots->length(); ++i) {
1247 (*args_slots)[i] = ComputeSlotForNextArgument(&it, data, frame);
1248 }
1249 return;
1250 }
1251 frames_to_skip--;
1252 }
1253 }
1254
1255 UNREACHABLE();
1256}
1257
1258
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001259} } // namespace v8::internal