Fix bug in environment simulation after inlined call-as-function.

This change is based on my previous change enabling inlining calls-as-function
fixing the bugs related to deoptimization.

The function value on top of the environment was dropped too late in the old code.
As a result we could get a wrong value on top after deoptimization.

This change includes r9619. It was reverted because of test failures that are fixed
with this patch.
Review URL: http://codereview.chromium.org/8360001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9758 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f630ff0c
...@@ -882,10 +882,12 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, ...@@ -882,10 +882,12 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
unsigned output_offset = unsigned output_offset =
output->GetOffsetFromSlotIndex(this, output_index); output->GetOffsetFromSlotIndex(this, output_index);
if (FLAG_trace_osr) { if (FLAG_trace_osr) {
PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d]\n", PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
output_offset, output_offset,
input_value, input_value,
*input_offset); *input_offset);
reinterpret_cast<Object*>(input_value)->ShortPrint();
PrintF("\n");
} }
output->SetFrameSlot(output_offset, input_value); output->SetFrameSlot(output_offset, input_value);
break; break;
......
...@@ -164,10 +164,11 @@ void HBasicBlock::Finish(HControlInstruction* end) { ...@@ -164,10 +164,11 @@ void HBasicBlock::Finish(HControlInstruction* end) {
} }
void HBasicBlock::Goto(HBasicBlock* block) { void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) {
if (block->IsInlineReturnTarget()) { if (block->IsInlineReturnTarget()) {
AddInstruction(new(zone()) HLeaveInlined); AddInstruction(new(zone()) HLeaveInlined);
last_environment_ = last_environment()->outer(); last_environment_ = last_environment()->outer();
if (drop_extra) last_environment_->Drop(1);
} }
AddSimulate(AstNode::kNoNumber); AddSimulate(AstNode::kNoNumber);
HGoto* instr = new(zone()) HGoto(block); HGoto* instr = new(zone()) HGoto(block);
...@@ -175,11 +176,14 @@ void HBasicBlock::Goto(HBasicBlock* block) { ...@@ -175,11 +176,14 @@ void HBasicBlock::Goto(HBasicBlock* block) {
} }
void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { void HBasicBlock::AddLeaveInlined(HValue* return_value,
HBasicBlock* target,
bool drop_extra) {
ASSERT(target->IsInlineReturnTarget()); ASSERT(target->IsInlineReturnTarget());
ASSERT(return_value != NULL); ASSERT(return_value != NULL);
AddInstruction(new(zone()) HLeaveInlined); AddInstruction(new(zone()) HLeaveInlined);
last_environment_ = last_environment()->outer(); last_environment_ = last_environment()->outer();
if (drop_extra) last_environment_->Drop(1);
last_environment()->Push(return_value); last_environment()->Push(return_value);
AddSimulate(AstNode::kNoNumber); AddSimulate(AstNode::kNoNumber);
HGoto* instr = new(zone()) HGoto(target); HGoto* instr = new(zone()) HGoto(target);
...@@ -541,7 +545,7 @@ HConstant* HGraph::GetConstantHole() { ...@@ -541,7 +545,7 @@ HConstant* HGraph::GetConstantHole() {
HGraphBuilder::HGraphBuilder(CompilationInfo* info, HGraphBuilder::HGraphBuilder(CompilationInfo* info,
TypeFeedbackOracle* oracle) TypeFeedbackOracle* oracle)
: function_state_(NULL), : function_state_(NULL),
initial_function_state_(this, info, oracle), initial_function_state_(this, info, oracle, false),
ast_context_(NULL), ast_context_(NULL),
break_scope_(NULL), break_scope_(NULL),
graph_(NULL), graph_(NULL),
...@@ -2005,11 +2009,13 @@ void HGraph::ComputeMinusZeroChecks() { ...@@ -2005,11 +2009,13 @@ void HGraph::ComputeMinusZeroChecks() {
// a (possibly inlined) function. // a (possibly inlined) function.
FunctionState::FunctionState(HGraphBuilder* owner, FunctionState::FunctionState(HGraphBuilder* owner,
CompilationInfo* info, CompilationInfo* info,
TypeFeedbackOracle* oracle) TypeFeedbackOracle* oracle,
bool drop_extra)
: owner_(owner), : owner_(owner),
compilation_info_(info), compilation_info_(info),
oracle_(oracle), oracle_(oracle),
call_context_(NULL), call_context_(NULL),
drop_extra_(drop_extra),
function_return_(NULL), function_return_(NULL),
test_context_(NULL), test_context_(NULL),
outer_(owner->function_state()) { outer_(owner->function_state()) {
...@@ -2168,8 +2174,8 @@ void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { ...@@ -2168,8 +2174,8 @@ void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) {
instr->SetSuccessorAt(0, empty_true); instr->SetSuccessorAt(0, empty_true);
instr->SetSuccessorAt(1, empty_false); instr->SetSuccessorAt(1, empty_false);
owner()->current_block()->Finish(instr); owner()->current_block()->Finish(instr);
empty_true->Goto(if_true()); empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
empty_false->Goto(if_false()); empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
owner()->set_current_block(NULL); owner()->set_current_block(NULL);
} }
...@@ -2190,8 +2196,8 @@ void TestContext::BuildBranch(HValue* value) { ...@@ -2190,8 +2196,8 @@ void TestContext::BuildBranch(HValue* value) {
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
builder->current_block()->Finish(test); builder->current_block()->Finish(test);
empty_true->Goto(if_true()); empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
empty_false->Goto(if_false()); empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
builder->set_current_block(NULL); builder->set_current_block(NULL);
} }
...@@ -2652,12 +2658,14 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { ...@@ -2652,12 +2658,14 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
test->if_false()); test->if_false());
} else if (context->IsEffect()) { } else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression())); CHECK_ALIVE(VisitForEffect(stmt->expression()));
current_block()->Goto(function_return()); current_block()->Goto(function_return(), function_state()->drop_extra());
} else { } else {
ASSERT(context->IsValue()); ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression())); CHECK_ALIVE(VisitForValue(stmt->expression()));
HValue* return_value = environment()->Pop(); HValue* return_value = environment()->Pop();
current_block()->AddLeaveInlined(return_value, function_return()); current_block()->AddLeaveInlined(return_value,
function_return(),
function_state()->drop_extra());
} }
set_current_block(NULL); set_current_block(NULL);
} }
...@@ -4546,7 +4554,7 @@ void HGraphBuilder::TraceInline(Handle<JSFunction> target, ...@@ -4546,7 +4554,7 @@ void HGraphBuilder::TraceInline(Handle<JSFunction> target,
} }
bool HGraphBuilder::TryInline(Call* expr) { bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
if (!FLAG_use_inlining) return false; if (!FLAG_use_inlining) return false;
// The function call we are inlining is a method call if the call // The function call we are inlining is a method call if the call
...@@ -4574,9 +4582,9 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4574,9 +4582,9 @@ bool HGraphBuilder::TryInline(Call* expr) {
return false; return false;
} }
CompilationInfo* outer_info = info();
#if !defined(V8_TARGET_ARCH_IA32) #if !defined(V8_TARGET_ARCH_IA32)
// Target must be able to use caller's context. // Target must be able to use caller's context.
CompilationInfo* outer_info = info();
if (target->context() != outer_info->closure()->context() || if (target->context() != outer_info->closure()->context() ||
outer_info->scope()->contains_with() || outer_info->scope()->contains_with() ||
outer_info->scope()->num_heap_slots() > 0) { outer_info->scope()->num_heap_slots() > 0) {
...@@ -4599,9 +4607,13 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4599,9 +4607,13 @@ bool HGraphBuilder::TryInline(Call* expr) {
} }
// Don't inline recursive functions. // Don't inline recursive functions.
if (*target_shared == outer_info->closure()->shared()) { for (FunctionState* state = function_state();
TraceInline(target, caller, "target is recursive"); state != NULL;
return false; state = state->outer()) {
if (state->compilation_info()->closure()->shared() == *target_shared) {
TraceInline(target, caller, "target is recursive");
return false;
}
} }
// We don't want to add more than a certain number of nodes from inlining. // We don't want to add more than a certain number of nodes from inlining.
...@@ -4698,7 +4710,7 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4698,7 +4710,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
Handle<Code>(target_shared->code()), Handle<Code>(target_shared->code()),
Handle<Context>(target->context()->global_context()), Handle<Context>(target->context()->global_context()),
isolate()); isolate());
FunctionState target_state(this, &target_info, &target_oracle); FunctionState target_state(this, &target_info, &target_oracle, drop_extra);
HConstant* undefined = graph()->GetConstantUndefined(); HConstant* undefined = graph()->GetConstantUndefined();
HEnvironment* inner_env = HEnvironment* inner_env =
...@@ -4747,9 +4759,11 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4747,9 +4759,11 @@ bool HGraphBuilder::TryInline(Call* expr) {
ASSERT(function_return() != NULL); ASSERT(function_return() != NULL);
ASSERT(call_context()->IsEffect() || call_context()->IsValue()); ASSERT(call_context()->IsEffect() || call_context()->IsValue());
if (call_context()->IsEffect()) { if (call_context()->IsEffect()) {
current_block()->Goto(function_return()); current_block()->Goto(function_return(), drop_extra);
} else { } else {
current_block()->AddLeaveInlined(undefined, function_return()); current_block()->AddLeaveInlined(undefined,
function_return(),
drop_extra);
} }
} else { } else {
// The graph builder assumes control can reach both branches of a // The graph builder assumes control can reach both branches of a
...@@ -4757,13 +4771,14 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4757,13 +4771,14 @@ bool HGraphBuilder::TryInline(Call* expr) {
// simply jumping to the false target. // simply jumping to the false target.
// //
// TODO(3168478): refactor to avoid this. // TODO(3168478): refactor to avoid this.
ASSERT(call_context()->IsTest());
HBasicBlock* empty_true = graph()->CreateBasicBlock(); HBasicBlock* empty_true = graph()->CreateBasicBlock();
HBasicBlock* empty_false = graph()->CreateBasicBlock(); HBasicBlock* empty_false = graph()->CreateBasicBlock();
HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false);
current_block()->Finish(test); current_block()->Finish(test);
empty_true->Goto(inlined_test_context()->if_true()); empty_true->Goto(inlined_test_context()->if_true(), drop_extra);
empty_false->Goto(inlined_test_context()->if_false()); empty_false->Goto(inlined_test_context()->if_false(), drop_extra);
} }
} }
...@@ -4780,12 +4795,12 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4780,12 +4795,12 @@ bool HGraphBuilder::TryInline(Call* expr) {
if (if_true->HasPredecessor()) { if (if_true->HasPredecessor()) {
if_true->SetJoinId(expr->id()); if_true->SetJoinId(expr->id());
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
if_true->Goto(true_target); if_true->Goto(true_target, drop_extra);
} }
if (if_false->HasPredecessor()) { if (if_false->HasPredecessor()) {
if_false->SetJoinId(expr->id()); if_false->SetJoinId(expr->id());
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
if_false->Goto(false_target); if_false->Goto(false_target, drop_extra);
} }
set_current_block(NULL); set_current_block(NULL);
...@@ -5102,26 +5117,7 @@ void HGraphBuilder::VisitCall(Call* expr) { ...@@ -5102,26 +5117,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
PushAndAdd(receiver); PushAndAdd(receiver);
CHECK_ALIVE(VisitExpressions(expr->arguments())); CHECK_ALIVE(VisitExpressions(expr->arguments()));
AddInstruction(new(zone()) HCheckFunction(function, expr->target())); AddInstruction(new(zone()) HCheckFunction(function, expr->target()));
if (TryInline(expr)) { if (TryInline(expr, true)) { // Drop function from environment.
// The function is lingering in the deoptimization environment.
// Handle it by case analysis on the AST context.
if (ast_context()->IsEffect()) {
Drop(1);
} else if (ast_context()->IsValue()) {
HValue* result = Pop();
Drop(1);
Push(result);
} else if (ast_context()->IsTest()) {
TestContext* context = TestContext::cast(ast_context());
if (context->if_true()->HasPredecessor()) {
context->if_true()->last_environment()->Drop(1);
}
if (context->if_false()->HasPredecessor()) {
context->if_true()->last_environment()->Drop(1);
}
} else {
UNREACHABLE();
}
return; return;
} else { } else {
call = PreProcessCall(new(zone()) HInvokeFunction(context, call = PreProcessCall(new(zone()) HInvokeFunction(context,
...@@ -5337,7 +5333,6 @@ void HGraphBuilder::VisitBitNot(UnaryOperation* expr) { ...@@ -5337,7 +5333,6 @@ void HGraphBuilder::VisitBitNot(UnaryOperation* expr) {
void HGraphBuilder::VisitNot(UnaryOperation* expr) { void HGraphBuilder::VisitNot(UnaryOperation* expr) {
// TODO(svenpanne) Perhaps a switch/virtual function is nicer here.
if (ast_context()->IsTest()) { if (ast_context()->IsTest()) {
TestContext* context = TestContext::cast(ast_context()); TestContext* context = TestContext::cast(ast_context());
VisitForControl(expr->expression(), VisitForControl(expr->expression(),
......
...@@ -121,7 +121,7 @@ class HBasicBlock: public ZoneObject { ...@@ -121,7 +121,7 @@ class HBasicBlock: public ZoneObject {
void Finish(HControlInstruction* last); void Finish(HControlInstruction* last);
void FinishExit(HControlInstruction* instruction); void FinishExit(HControlInstruction* instruction);
void Goto(HBasicBlock* block); void Goto(HBasicBlock* block, bool drop_extra = false);
int PredecessorIndexOf(HBasicBlock* predecessor) const; int PredecessorIndexOf(HBasicBlock* predecessor) const;
void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); } void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
...@@ -133,7 +133,9 @@ class HBasicBlock: public ZoneObject { ...@@ -133,7 +133,9 @@ class HBasicBlock: public ZoneObject {
// Add the inlined function exit sequence, adding an HLeaveInlined // Add the inlined function exit sequence, adding an HLeaveInlined
// instruction and updating the bailout environment. // instruction and updating the bailout environment.
void AddLeaveInlined(HValue* return_value, HBasicBlock* target); void AddLeaveInlined(HValue* return_value,
HBasicBlock* target,
bool drop_extra = false);
// If a target block is tagged as an inline function return, all // If a target block is tagged as an inline function return, all
// predecessors should contain the inlined exit sequence: // predecessors should contain the inlined exit sequence:
...@@ -607,12 +609,14 @@ class FunctionState BASE_EMBEDDED { ...@@ -607,12 +609,14 @@ class FunctionState BASE_EMBEDDED {
public: public:
FunctionState(HGraphBuilder* owner, FunctionState(HGraphBuilder* owner,
CompilationInfo* info, CompilationInfo* info,
TypeFeedbackOracle* oracle); TypeFeedbackOracle* oracle,
bool drop_extra);
~FunctionState(); ~FunctionState();
CompilationInfo* compilation_info() { return compilation_info_; } CompilationInfo* compilation_info() { return compilation_info_; }
TypeFeedbackOracle* oracle() { return oracle_; } TypeFeedbackOracle* oracle() { return oracle_; }
AstContext* call_context() { return call_context_; } AstContext* call_context() { return call_context_; }
bool drop_extra() { return drop_extra_; }
HBasicBlock* function_return() { return function_return_; } HBasicBlock* function_return() { return function_return_; }
TestContext* test_context() { return test_context_; } TestContext* test_context() { return test_context_; }
void ClearInlinedTestContext() { void ClearInlinedTestContext() {
...@@ -632,6 +636,10 @@ class FunctionState BASE_EMBEDDED { ...@@ -632,6 +636,10 @@ class FunctionState BASE_EMBEDDED {
// inlined. NULL when not inlining. // inlined. NULL when not inlining.
AstContext* call_context_; AstContext* call_context_;
// Indicate if we have to drop an extra value from the environment on
// return from inlined functions.
bool drop_extra_;
// When inlining in an effect of value context, this is the return block. // When inlining in an effect of value context, this is the return block.
// It is NULL otherwise. When inlining in a test context, there are a // It is NULL otherwise. When inlining in a test context, there are a
// pair of return blocks in the context. When not inlining, there is no // pair of return blocks in the context. When not inlining, there is no
...@@ -728,6 +736,8 @@ class HGraphBuilder: public AstVisitor { ...@@ -728,6 +736,8 @@ class HGraphBuilder: public AstVisitor {
TypeFeedbackOracle* oracle() const { return function_state()->oracle(); } TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
FunctionState* function_state() const { return function_state_; }
private: private:
// Type of a member function that generates inline code for a native function. // Type of a member function that generates inline code for a native function.
typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call); typedef void (HGraphBuilder::*InlineFunctionGenerator)(CallRuntime* call);
...@@ -746,7 +756,6 @@ class HGraphBuilder: public AstVisitor { ...@@ -746,7 +756,6 @@ class HGraphBuilder: public AstVisitor {
static const int kMaxSourceSize = 600; static const int kMaxSourceSize = 600;
// Simple accessors. // Simple accessors.
FunctionState* function_state() const { return function_state_; }
void set_function_state(FunctionState* state) { function_state_ = state; } void set_function_state(FunctionState* state) { function_state_ = state; }
AstContext* ast_context() const { return ast_context_; } AstContext* ast_context() const { return ast_context_; }
...@@ -883,7 +892,7 @@ class HGraphBuilder: public AstVisitor { ...@@ -883,7 +892,7 @@ class HGraphBuilder: public AstVisitor {
// Try to optimize fun.apply(receiver, arguments) pattern. // Try to optimize fun.apply(receiver, arguments) pattern.
bool TryCallApply(Call* expr); bool TryCallApply(Call* expr);
bool TryInline(Call* expr); bool TryInline(Call* expr, bool drop_extra = false);
bool TryInlineBuiltinFunction(Call* expr, bool TryInlineBuiltinFunction(Call* expr,
HValue* receiver, HValue* receiver,
Handle<Map> receiver_map, Handle<Map> receiver_map,
......
...@@ -2155,7 +2155,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { ...@@ -2155,7 +2155,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
} }
CallFunctionStub stub(arg_count, flags); CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub); __ CallStub(&stub, expr->id());
if (record_call_target) { if (record_call_target) {
// There is a one element cache in the instruction stream. // There is a one element cache in the instruction stream.
#ifdef DEBUG #ifdef DEBUG
......
...@@ -504,61 +504,56 @@ void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos, ...@@ -504,61 +504,56 @@ void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) { void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
for (int i = 0; i < infos->length(); i++) { for (int i = 0; i < infos->length(); i++) {
Address target_address = (*infos)[i].target_address(); RelocInfo reloc_entry = (*infos)[i];
Address target_address = reloc_entry.target_address();
unsigned ast_id = static_cast<unsigned>((*infos)[i].data()); unsigned ast_id = static_cast<unsigned>((*infos)[i].data());
ProcessTargetAt(target_address, ast_id); Code* target = Code::GetCodeFromTargetAddress(target_address);
} switch (target->kind()) {
} case Code::LOAD_IC:
case Code::STORE_IC:
case Code::CALL_IC:
case Code::KEYED_CALL_IC:
if (target->ic_state() == MONOMORPHIC) {
if (target->kind() == Code::CALL_IC &&
target->check_type() != RECEIVER_MAP_CHECK) {
SetInfo(ast_id, Smi::FromInt(target->check_type()));
} else {
Object* map = target->FindFirstMap();
SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
}
} else if (target->ic_state() == MEGAMORPHIC) {
SetInfo(ast_id, target);
}
break;
void TypeFeedbackOracle::ProcessTargetAt(Address target_address, case Code::KEYED_LOAD_IC:
unsigned ast_id) { case Code::KEYED_STORE_IC:
Code* target = Code::GetCodeFromTargetAddress(target_address); if (target->ic_state() == MONOMORPHIC ||
switch (target->kind()) { target->ic_state() == MEGAMORPHIC) {
case Code::LOAD_IC: SetInfo(ast_id, target);
case Code::STORE_IC:
case Code::CALL_IC:
case Code::KEYED_CALL_IC:
if (target->ic_state() == MONOMORPHIC) {
if (target->kind() == Code::CALL_IC &&
target->check_type() != RECEIVER_MAP_CHECK) {
SetInfo(ast_id, Smi::FromInt(target->check_type()));
} else {
Object* map = target->FindFirstMap();
SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
} }
} else if (target->ic_state() == MEGAMORPHIC) { break;
SetInfo(ast_id, target);
}
break;
case Code::KEYED_LOAD_IC: case Code::UNARY_OP_IC:
case Code::KEYED_STORE_IC: case Code::BINARY_OP_IC:
if (target->ic_state() == MONOMORPHIC || case Code::COMPARE_IC:
target->ic_state() == MEGAMORPHIC) { case Code::TO_BOOLEAN_IC:
SetInfo(ast_id, target); SetInfo(ast_id, target);
} break;
break;
case Code::STUB:
case Code::UNARY_OP_IC: if (target->major_key() == CodeStub::CallFunction &&
case Code::BINARY_OP_IC: target->has_function_cache()) {
case Code::COMPARE_IC: Object* value = CallFunctionStub::GetCachedValue(reloc_entry.pc());
case Code::TO_BOOLEAN_IC: if (value->IsJSFunction()) {
SetInfo(ast_id, target); SetInfo(ast_id, value);
break; }
case Code::STUB:
if (target->major_key() == CodeStub::CallFunction &&
target->has_function_cache()) {
Object* value = CallFunctionStub::GetCachedValue(target_address);
if (value->IsJSFunction()) {
SetInfo(ast_id, value);
} }
} break;
break;
default: default:
break; break;
}
} }
} }
......
...@@ -277,7 +277,6 @@ class TypeFeedbackOracle BASE_EMBEDDED { ...@@ -277,7 +277,6 @@ class TypeFeedbackOracle BASE_EMBEDDED {
byte* old_start, byte* old_start,
byte* new_start); byte* new_start);
void ProcessRelocInfos(ZoneList<RelocInfo>* infos); void ProcessRelocInfos(ZoneList<RelocInfo>* infos);
void ProcessTargetAt(Address target_address, unsigned ast_id);
// Returns an element from the backing store. Returns undefined if // Returns an element from the backing store. Returns undefined if
// there is no information. // there is no information.
......
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test deoptimization after inlined call.
function bar(a, b) {try { return a; } finally { } }
function test_context() {
function foo(x) { return 42; }
var s, t;
for (var i = 0x7ff00000; i < 0x80000000; i++) {
bar(t = foo(i) ? bar(42 + i - i) : bar(0), s = i + t);
}
return s;
}
assertEquals(0x7fffffff + 42, test_context());
function value_context() {
function foo(x) { return 42; }
var s, t;
for (var i = 0x7ff00000; i < 0x80000000; i++) {
bar(t = foo(i), s = i + t);
}
return s;
}
assertEquals(0x7fffffff + 42, value_context());
function effect_context() {
function foo(x) { return 42; }
var s, t;
for (var i = 0x7ff00000; i < 0x80000000; i++) {
bar(foo(i), s = i + 42);
}
return s;
}
assertEquals(0x7fffffff + 42, effect_context());
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