Commit 616dbf76 authored by vegorov@chromium.org's avatar vegorov@chromium.org

Always iterate outgoing arguments as a part of caller frame.

Change caller_sp() to always point to the place after outgoing arguments.

Change deoptimizer to use absolute stack slot addresses for deferred HeapNumber's materialization.

(This is reapplication of r7504 with fix for mozilla testsuite failures).

Review URL: http://codereview.chromium.org/6677164

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7516 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 058d82a3
...@@ -218,8 +218,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate, ...@@ -218,8 +218,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
fp_to_sp_delta_(fp_to_sp_delta), fp_to_sp_delta_(fp_to_sp_delta),
output_count_(0), output_count_(0),
output_(NULL), output_(NULL),
integer32_values_(NULL), deferred_heap_numbers_(0) {
double_values_(NULL) {
if (FLAG_trace_deopt && type != OSR) { if (FLAG_trace_deopt && type != OSR) {
PrintF("**** DEOPT: "); PrintF("**** DEOPT: ");
function->PrintName(); function->PrintName();
...@@ -258,8 +257,6 @@ Deoptimizer::Deoptimizer(Isolate* isolate, ...@@ -258,8 +257,6 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
Deoptimizer::~Deoptimizer() { Deoptimizer::~Deoptimizer() {
ASSERT(input_ == NULL && output_ == NULL); ASSERT(input_ == NULL && output_ == NULL);
delete[] integer32_values_;
delete[] double_values_;
} }
...@@ -390,13 +387,8 @@ void Deoptimizer::DoComputeOutputFrames() { ...@@ -390,13 +387,8 @@ void Deoptimizer::DoComputeOutputFrames() {
int count = iterator.Next(); int count = iterator.Next();
ASSERT(output_ == NULL); ASSERT(output_ == NULL);
output_ = new FrameDescription*[count]; output_ = new FrameDescription*[count];
// Per-frame lists of untagged and unboxed int32 and double values.
integer32_values_ = new List<ValueDescriptionInteger32>[count];
double_values_ = new List<ValueDescriptionDouble>[count];
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
output_[i] = NULL; output_[i] = NULL;
integer32_values_[i].Initialize(0);
double_values_[i].Initialize(0);
} }
output_count_ = count; output_count_ = count;
...@@ -424,40 +416,22 @@ void Deoptimizer::DoComputeOutputFrames() { ...@@ -424,40 +416,22 @@ void Deoptimizer::DoComputeOutputFrames() {
} }
void Deoptimizer::InsertHeapNumberValues(int index, JavaScriptFrame* frame) { void Deoptimizer::MaterializeHeapNumbers() {
// We need to adjust the stack index by one for the top-most frame. for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
int extra_slot_count = (index == output_count() - 1) ? 1 : 0; HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
List<ValueDescriptionInteger32>* ints = &integer32_values_[index]; Handle<Object> num = isolate_->factory()->NewNumber(d.value());
for (int i = 0; i < ints->length(); i++) { if (FLAG_trace_deopt) {
ValueDescriptionInteger32 value = ints->at(i); PrintF("Materializing a new heap number %p [%e] in slot %p\n",
double val = static_cast<double>(value.int32_value()); reinterpret_cast<void*>(*num),
InsertHeapNumberValue(frame, value.stack_index(), val, extra_slot_count); d.value(),
} d.slot_address());
}
// Iterate over double values and convert them to a heap number. Memory::Object_at(d.slot_address()) = *num;
List<ValueDescriptionDouble>* doubles = &double_values_[index];
for (int i = 0; i < doubles->length(); ++i) {
ValueDescriptionDouble value = doubles->at(i);
InsertHeapNumberValue(frame, value.stack_index(), value.double_value(),
extra_slot_count);
} }
} }
void Deoptimizer::InsertHeapNumberValue(JavaScriptFrame* frame,
int stack_index,
double val,
int extra_slot_count) {
// Add one to the TOS index to take the 'state' pushed before jumping
// to the stub that calls Runtime::NotifyDeoptimized into account.
int tos_index = stack_index + extra_slot_count;
int index = (frame->ComputeExpressionsCount() - 1) - tos_index;
if (FLAG_trace_deopt) PrintF("Allocating a new heap number: %e\n", val);
Handle<Object> num = isolate_->factory()->NewNumber(val);
frame->SetExpression(index, *num);
}
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
int frame_index, int frame_index,
unsigned output_offset) { unsigned output_offset) {
...@@ -500,7 +474,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -500,7 +474,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
int input_reg = iterator->Next(); int input_reg = iterator->Next();
intptr_t value = input_->GetRegister(input_reg); intptr_t value = input_->GetRegister(input_reg);
bool is_smi = Smi::IsValid(value); bool is_smi = Smi::IsValid(value);
unsigned output_index = output_offset / kPointerSize;
if (FLAG_trace_deopt) { if (FLAG_trace_deopt) {
PrintF( PrintF(
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n", " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
...@@ -517,9 +490,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -517,9 +490,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
} else { } else {
// We save the untagged value on the side and store a GC-safe // We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame. // temporary placeholder in the frame.
AddInteger32Value(frame_index, AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
output_index, static_cast<double>(static_cast<int32_t>(value)));
static_cast<int32_t>(value));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
} }
return; return;
...@@ -528,7 +500,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -528,7 +500,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
case Translation::DOUBLE_REGISTER: { case Translation::DOUBLE_REGISTER: {
int input_reg = iterator->Next(); int input_reg = iterator->Next();
double value = input_->GetDoubleRegister(input_reg); double value = input_->GetDoubleRegister(input_reg);
unsigned output_index = output_offset / kPointerSize;
if (FLAG_trace_deopt) { if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n", PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
output_[frame_index]->GetTop() + output_offset, output_[frame_index]->GetTop() + output_offset,
...@@ -538,7 +509,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -538,7 +509,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
} }
// We save the untagged value on the side and store a GC-safe // We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame. // temporary placeholder in the frame.
AddDoubleValue(frame_index, output_index, value); AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
return; return;
} }
...@@ -566,7 +537,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -566,7 +537,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
input_->GetOffsetFromSlotIndex(this, input_slot_index); input_->GetOffsetFromSlotIndex(this, input_slot_index);
intptr_t value = input_->GetFrameSlot(input_offset); intptr_t value = input_->GetFrameSlot(input_offset);
bool is_smi = Smi::IsValid(value); bool is_smi = Smi::IsValid(value);
unsigned output_index = output_offset / kPointerSize;
if (FLAG_trace_deopt) { if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": ", PrintF(" 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset); output_[frame_index]->GetTop() + output_offset);
...@@ -583,9 +553,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -583,9 +553,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
} else { } else {
// We save the untagged value on the side and store a GC-safe // We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame. // temporary placeholder in the frame.
AddInteger32Value(frame_index, AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
output_index, static_cast<double>(static_cast<int32_t>(value)));
static_cast<int32_t>(value));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
} }
return; return;
...@@ -596,7 +565,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -596,7 +565,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
unsigned input_offset = unsigned input_offset =
input_->GetOffsetFromSlotIndex(this, input_slot_index); input_->GetOffsetFromSlotIndex(this, input_slot_index);
double value = input_->GetDoubleFrameSlot(input_offset); double value = input_->GetDoubleFrameSlot(input_offset);
unsigned output_index = output_offset / kPointerSize;
if (FLAG_trace_deopt) { if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n", PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
output_[frame_index]->GetTop() + output_offset, output_[frame_index]->GetTop() + output_offset,
...@@ -606,7 +574,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, ...@@ -606,7 +574,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
} }
// We save the untagged value on the side and store a GC-safe // We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame. // temporary placeholder in the frame.
AddDoubleValue(frame_index, output_index, value); AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
return; return;
} }
...@@ -910,19 +878,11 @@ Object* Deoptimizer::ComputeLiteral(int index) const { ...@@ -910,19 +878,11 @@ Object* Deoptimizer::ComputeLiteral(int index) const {
} }
void Deoptimizer::AddInteger32Value(int frame_index, void Deoptimizer::AddDoubleValue(intptr_t slot_address,
int slot_index,
int32_t value) {
ValueDescriptionInteger32 value_desc(slot_index, value);
integer32_values_[frame_index].Add(value_desc);
}
void Deoptimizer::AddDoubleValue(int frame_index,
int slot_index,
double value) { double value) {
ValueDescriptionDouble value_desc(slot_index, value); HeapNumberMaterializationDescriptor value_desc(
double_values_[frame_index].Add(value_desc); reinterpret_cast<Address>(slot_address), value);
deferred_heap_numbers_.Add(value_desc);
} }
......
...@@ -42,38 +42,17 @@ class TranslationIterator; ...@@ -42,38 +42,17 @@ class TranslationIterator;
class DeoptimizingCodeListNode; class DeoptimizingCodeListNode;
class ValueDescription BASE_EMBEDDED { class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
public: public:
explicit ValueDescription(int index) : stack_index_(index) { } HeapNumberMaterializationDescriptor(Address slot_address, double val)
int stack_index() const { return stack_index_; } : slot_address_(slot_address), val_(val) { }
private:
// Offset relative to the top of the stack.
int stack_index_;
};
class ValueDescriptionInteger32: public ValueDescription {
public:
ValueDescriptionInteger32(int index, int32_t value)
: ValueDescription(index), int32_value_(value) { }
int32_t int32_value() const { return int32_value_; }
private:
// Raw value.
int32_t int32_value_;
};
Address slot_address() const { return slot_address_; }
class ValueDescriptionDouble: public ValueDescription { double value() const { return val_; }
public:
ValueDescriptionDouble(int index, double value)
: ValueDescription(index), double_value_(value) { }
double double_value() const { return double_value_; }
private: private:
// Raw value. Address slot_address_;
double double_value_; double val_;
}; };
...@@ -190,7 +169,7 @@ class Deoptimizer : public Malloced { ...@@ -190,7 +169,7 @@ class Deoptimizer : public Malloced {
~Deoptimizer(); ~Deoptimizer();
void InsertHeapNumberValues(int index, JavaScriptFrame* frame); void MaterializeHeapNumbers();
static void ComputeOutputFrames(Deoptimizer* deoptimizer); static void ComputeOutputFrames(Deoptimizer* deoptimizer);
...@@ -277,13 +256,7 @@ class Deoptimizer : public Malloced { ...@@ -277,13 +256,7 @@ class Deoptimizer : public Malloced {
Object* ComputeLiteral(int index) const; Object* ComputeLiteral(int index) const;
void InsertHeapNumberValue(JavaScriptFrame* frame, void AddDoubleValue(intptr_t slot_address, double value);
int stack_index,
double val,
int extra_slot_count);
void AddInteger32Value(int frame_index, int slot_index, int32_t value);
void AddDoubleValue(int frame_index, int slot_index, double value);
static LargeObjectChunk* CreateCode(BailoutType type); static LargeObjectChunk* CreateCode(BailoutType type);
static void GenerateDeoptimizationEntries( static void GenerateDeoptimizationEntries(
...@@ -310,8 +283,7 @@ class Deoptimizer : public Malloced { ...@@ -310,8 +283,7 @@ class Deoptimizer : public Malloced {
// Array of output frame descriptions. // Array of output frame descriptions.
FrameDescription** output_; FrameDescription** output_;
List<ValueDescriptionInteger32>* integer32_values_; List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
List<ValueDescriptionDouble>* double_values_;
static int table_entry_size_; static int table_entry_size_;
......
...@@ -148,15 +148,26 @@ inline bool StandardFrame::IsConstructFrame(Address fp) { ...@@ -148,15 +148,26 @@ inline bool StandardFrame::IsConstructFrame(Address fp) {
} }
Address JavaScriptFrame::GetParameterSlot(int index) const {
int param_count = ComputeParametersCount();
ASSERT(-1 <= index && index < param_count);
int parameter_offset = (param_count - index - 1) * kPointerSize;
return caller_sp() + parameter_offset;
}
Object* JavaScriptFrame::GetParameter(int index) const {
return Memory::Object_at(GetParameterSlot(index));
}
inline Object* JavaScriptFrame::receiver() const { inline Object* JavaScriptFrame::receiver() const {
const int offset = JavaScriptFrameConstants::kReceiverOffset; return GetParameter(-1);
return Memory::Object_at(caller_sp() + offset);
} }
inline void JavaScriptFrame::set_receiver(Object* value) { inline void JavaScriptFrame::set_receiver(Object* value) {
const int offset = JavaScriptFrameConstants::kReceiverOffset; Memory::Object_at(GetParameterSlot(-1)) = value;
Memory::Object_at(caller_sp() + offset) = value;
} }
......
...@@ -579,9 +579,7 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { ...@@ -579,9 +579,7 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const {
isolate(), pc(), &safepoint_entry, &stack_slots); isolate(), pc(), &safepoint_entry, &stack_slots);
unsigned slot_space = stack_slots * kPointerSize; unsigned slot_space = stack_slots * kPointerSize;
// Visit the outgoing parameters. This is usually dealt with by the // Visit the outgoing parameters.
// callee, but while GC'ing we artificially lower the number of
// arguments to zero and let the caller deal with it.
Object** parameters_base = &Memory::Object_at(sp()); Object** parameters_base = &Memory::Object_at(sp());
Object** parameters_limit = &Memory::Object_at( Object** parameters_limit = &Memory::Object_at(
fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space); fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
...@@ -635,21 +633,6 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { ...@@ -635,21 +633,6 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const {
// Visit the return address in the callee and incoming arguments. // Visit the return address in the callee and incoming arguments.
IteratePc(v, pc_address(), code); IteratePc(v, pc_address(), code);
IterateArguments(v);
}
Object* JavaScriptFrame::GetParameter(int index) const {
ASSERT(index >= 0 && index < ComputeParametersCount());
const int offset = JavaScriptFrameConstants::kParam0Offset;
return Memory::Object_at(caller_sp() + offset - (index * kPointerSize));
}
int JavaScriptFrame::ComputeParametersCount() const {
Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset;
Address limit = fp() + JavaScriptFrameConstants::kLastParameterOffset;
return static_cast<int>((base - limit) / kPointerSize);
} }
...@@ -669,27 +652,17 @@ Code* JavaScriptFrame::unchecked_code() const { ...@@ -669,27 +652,17 @@ Code* JavaScriptFrame::unchecked_code() const {
} }
int JavaScriptFrame::GetNumberOfIncomingArguments() const {
ASSERT(!SafeStackFrameIterator::is_active(isolate()) &&
isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
JSFunction* function = JSFunction::cast(this->function());
return function->shared()->formal_parameter_count();
}
Address JavaScriptFrame::GetCallerStackPointer() const { Address JavaScriptFrame::GetCallerStackPointer() const {
int arguments; return fp() + StandardFrameConstants::kCallerSPOffset;
if (SafeStackFrameIterator::is_active(isolate()) ||
isolate()->heap()->gc_state() != Heap::NOT_IN_GC) {
// If the we are currently iterating the safe stack the
// arguments for frames are traversed as if they were
// expression stack elements of the calling frame. The reason for
// this rather strange decision is that we cannot access the
// function during mark-compact GCs when objects may have been marked.
// In fact accessing heap objects (like function->shared() below)
// at all during GC is problematic.
arguments = 0;
} else {
// Compute the number of arguments by getting the number of formal
// parameters of the function. We must remember to take the
// receiver into account (+1).
JSFunction* function = JSFunction::cast(this->function());
arguments = function->shared()->formal_parameter_count() + 1;
}
const int offset = StandardFrameConstants::kCallerSPOffset;
return fp() + offset + (arguments * kPointerSize);
} }
...@@ -867,9 +840,7 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) { ...@@ -867,9 +840,7 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
Address ArgumentsAdaptorFrame::GetCallerStackPointer() const { Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
const int arguments = Smi::cast(GetExpression(0))->value(); return fp() + StandardFrameConstants::kCallerSPOffset;
const int offset = StandardFrameConstants::kCallerSPOffset;
return fp() + offset + (arguments + 1) * kPointerSize;
} }
...@@ -1109,17 +1080,6 @@ void StandardFrame::IterateExpressions(ObjectVisitor* v) const { ...@@ -1109,17 +1080,6 @@ void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
void JavaScriptFrame::Iterate(ObjectVisitor* v) const { void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
IterateExpressions(v); IterateExpressions(v);
IteratePc(v, pc_address(), LookupCode()); IteratePc(v, pc_address(), LookupCode());
IterateArguments(v);
}
void JavaScriptFrame::IterateArguments(ObjectVisitor* v) const {
// Traverse callee-saved registers, receiver, and parameters.
const int kBaseOffset = JavaScriptFrameConstants::kLastParameterOffset;
const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
Object** base = &Memory::Object_at(fp() + kBaseOffset);
Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1;
v->VisitPointers(base, limit);
} }
......
...@@ -463,8 +463,11 @@ class JavaScriptFrame: public StandardFrame { ...@@ -463,8 +463,11 @@ class JavaScriptFrame: public StandardFrame {
inline void set_receiver(Object* value); inline void set_receiver(Object* value);
// Access the parameters. // Access the parameters.
Object* GetParameter(int index) const; inline Address GetParameterSlot(int index) const;
int ComputeParametersCount() const; inline Object* GetParameter(int index) const;
inline int ComputeParametersCount() const {
return GetNumberOfIncomingArguments();
}
// Check if this frame is a constructor frame invoked through 'new'. // Check if this frame is a constructor frame invoked through 'new'.
bool IsConstructor() const; bool IsConstructor() const;
...@@ -502,6 +505,8 @@ class JavaScriptFrame: public StandardFrame { ...@@ -502,6 +505,8 @@ class JavaScriptFrame: public StandardFrame {
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
virtual int GetNumberOfIncomingArguments() const;
// Garbage collection support. Iterates over incoming arguments, // Garbage collection support. Iterates over incoming arguments,
// receiver, and any callee-saved registers. // receiver, and any callee-saved registers.
void IterateArguments(ObjectVisitor* v) const; void IterateArguments(ObjectVisitor* v) const;
...@@ -562,6 +567,10 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame { ...@@ -562,6 +567,10 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame {
explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator) explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
: JavaScriptFrame(iterator) { } : JavaScriptFrame(iterator) { }
virtual int GetNumberOfIncomingArguments() const {
return Smi::cast(GetExpression(0))->value();
}
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
private: private:
......
...@@ -7323,14 +7323,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { ...@@ -7323,14 +7323,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
ASSERT(isolate->heap()->IsAllocationAllowed()); ASSERT(isolate->heap()->IsAllocationAllowed());
int frames = deoptimizer->output_count(); int frames = deoptimizer->output_count();
deoptimizer->MaterializeHeapNumbers();
delete deoptimizer;
JavaScriptFrameIterator it(isolate); JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = NULL; JavaScriptFrame* frame = NULL;
for (int i = 0; i < frames; i++) { for (int i = 0; i < frames - 1; i++) it.Advance();
if (i != 0) it.Advance(); frame = it.frame();
frame = it.frame();
deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
}
delete deoptimizer;
RUNTIME_ASSERT(frame->function()->IsJSFunction()); RUNTIME_ASSERT(frame->function()->IsJSFunction());
Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate); Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment