Index: src/hydrogen.cc |
=================================================================== |
--- src/hydrogen.cc (revision 9808) |
+++ src/hydrogen.cc (working copy) |
@@ -164,10 +164,11 @@ |
} |
-void HBasicBlock::Goto(HBasicBlock* block) { |
+void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { |
if (block->IsInlineReturnTarget()) { |
AddInstruction(new(zone()) HLeaveInlined); |
last_environment_ = last_environment()->outer(); |
+ if (drop_extra) last_environment_->Drop(1); |
} |
AddSimulate(AstNode::kNoNumber); |
HGoto* instr = new(zone()) HGoto(block); |
@@ -175,11 +176,14 @@ |
} |
-void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
+void HBasicBlock::AddLeaveInlined(HValue* return_value, |
+ HBasicBlock* target, |
+ bool drop_extra) { |
ASSERT(target->IsInlineReturnTarget()); |
ASSERT(return_value != NULL); |
AddInstruction(new(zone()) HLeaveInlined); |
last_environment_ = last_environment()->outer(); |
+ if (drop_extra) last_environment_->Drop(1); |
last_environment()->Push(return_value); |
AddSimulate(AstNode::kNoNumber); |
HGoto* instr = new(zone()) HGoto(target); |
@@ -541,7 +545,7 @@ |
HGraphBuilder::HGraphBuilder(CompilationInfo* info, |
TypeFeedbackOracle* oracle) |
: function_state_(NULL), |
- initial_function_state_(this, info, oracle), |
+ initial_function_state_(this, info, oracle, false), |
ast_context_(NULL), |
break_scope_(NULL), |
graph_(NULL), |
@@ -1499,6 +1503,9 @@ |
block->block_id() < dominated->block_id() && |
visited_on_paths_.Add(block->block_id())) { |
side_effects |= block_side_effects_[block->block_id()]; |
+ if (block->IsLoopHeader()) { |
+ side_effects |= loop_side_effects_[block->block_id()]; |
+ } |
side_effects |= CollectSideEffectsOnPathsToDominatedBlock( |
dominator, block); |
} |
@@ -2005,11 +2012,13 @@ |
// a (possibly inlined) function. |
FunctionState::FunctionState(HGraphBuilder* owner, |
CompilationInfo* info, |
- TypeFeedbackOracle* oracle) |
+ TypeFeedbackOracle* oracle, |
+ bool drop_extra) |
: owner_(owner), |
compilation_info_(info), |
oracle_(oracle), |
call_context_(NULL), |
+ drop_extra_(drop_extra), |
function_return_(NULL), |
test_context_(NULL), |
outer_(owner->function_state()) { |
@@ -2168,8 +2177,8 @@ |
instr->SetSuccessorAt(0, empty_true); |
instr->SetSuccessorAt(1, empty_false); |
owner()->current_block()->Finish(instr); |
- empty_true->Goto(if_true()); |
- empty_false->Goto(if_false()); |
+ empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
+ empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
owner()->set_current_block(NULL); |
} |
@@ -2190,8 +2199,8 @@ |
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); |
builder->current_block()->Finish(test); |
- empty_true->Goto(if_true()); |
- empty_false->Goto(if_false()); |
+ empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
+ empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
builder->set_current_block(NULL); |
} |
@@ -2652,12 +2661,14 @@ |
test->if_false()); |
} else if (context->IsEffect()) { |
CHECK_ALIVE(VisitForEffect(stmt->expression())); |
- current_block()->Goto(function_return()); |
+ current_block()->Goto(function_return(), function_state()->drop_extra()); |
} else { |
ASSERT(context->IsValue()); |
CHECK_ALIVE(VisitForValue(stmt->expression())); |
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); |
} |
@@ -3156,7 +3167,7 @@ |
return ast_context()->ReturnInstruction(instr, expr->id()); |
} |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
GlobalPropertyAccess type = |
LookupGlobalProperty(variable, &lookup, false); |
@@ -3276,7 +3287,7 @@ |
literal, |
name, |
value, |
- function_strict_mode()); |
+ function_strict_mode_flag()); |
AddInstruction(store); |
AddSimulate(key->id()); |
} else { |
@@ -3337,11 +3348,8 @@ |
HValue* value = Pop(); |
if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); |
- // Load the elements array before the first store. |
- if (elements == NULL) { |
- elements = new(zone()) HLoadElements(literal); |
- AddInstruction(elements); |
- } |
+ elements = new(zone()) HLoadElements(literal); |
+ AddInstruction(elements); |
HValue* key = AddInstruction( |
new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
@@ -3365,10 +3373,10 @@ |
set_current_block(check_smi_only_elements); |
HCompareConstantEqAndBranch* smi_elements_check = |
new(zone()) HCompareConstantEqAndBranch(elements_kind, |
- FAST_SMI_ONLY_ELEMENTS, |
+ FAST_ELEMENTS, |
Token::EQ_STRICT); |
- smi_elements_check->SetSuccessorAt(0, store_generic); |
- smi_elements_check->SetSuccessorAt(1, store_fast_edgesplit2); |
+ smi_elements_check->SetSuccessorAt(0, store_fast_edgesplit2); |
+ smi_elements_check->SetSuccessorAt(1, store_generic); |
current_block()->Finish(smi_elements_check); |
store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast)); |
@@ -3457,7 +3465,7 @@ |
object, |
name, |
value, |
- function_strict_mode()); |
+ function_strict_mode_flag()); |
} |
@@ -3471,7 +3479,7 @@ |
Handle<String> name = Handle<String>::cast(key->handle()); |
ASSERT(!name.is_null()); |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
SmallMapList* types = expr->GetReceiverTypes(); |
bool is_monomorphic = expr->IsMonomorphic() && |
ComputeStoredField(types->first(), name, &lookup); |
@@ -3495,7 +3503,7 @@ |
HBasicBlock* join = NULL; |
for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
Handle<Map> map = types->at(i); |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
if (ComputeStoredField(map, name, &lookup)) { |
if (count == 0) { |
AddInstruction(new(zone()) HCheckNonSmi(object)); // Only needed once. |
@@ -3578,7 +3586,7 @@ |
ASSERT(!name.is_null()); |
SmallMapList* types = expr->GetReceiverTypes(); |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
if (expr->IsMonomorphic()) { |
instr = BuildStoreNamed(object, value, expr); |
@@ -3623,7 +3631,7 @@ |
HValue* value, |
int position, |
int ast_id) { |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); |
if (type == kUseCell) { |
Handle<GlobalObject> global(info()->global_object()); |
@@ -3642,7 +3650,7 @@ |
global_object, |
var->name(), |
value, |
- function_strict_mode()); |
+ function_strict_mode_flag()); |
instr->set_position(position); |
AddInstruction(instr); |
ASSERT(instr->HasSideEffects()); |
@@ -3938,7 +3946,7 @@ |
Property* expr, |
Handle<Map> map, |
Handle<String> name) { |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
map->LookupInDescriptors(NULL, *name, &lookup); |
if (lookup.IsProperty() && lookup.type() == FIELD) { |
return BuildLoadNamedField(obj, |
@@ -4037,11 +4045,8 @@ |
HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
HValue* key, |
HValue* val, |
- Expression* expr, |
+ Handle<Map> map, |
bool is_store) { |
- ASSERT(expr->IsMonomorphic()); |
- Handle<Map> map = expr->GetMonomorphicReceiverType(); |
- AddInstruction(new(zone()) HCheckNonSmi(object)); |
HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); |
bool fast_smi_only_elements = map->has_fast_smi_only_elements(); |
bool fast_elements = map->has_fast_elements(); |
@@ -4091,7 +4096,6 @@ |
bool* has_side_effects) { |
*has_side_effects = false; |
AddInstruction(new(zone()) HCheckNonSmi(object)); |
- AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
SmallMapList* maps = prop->GetReceiverTypes(); |
bool todo_external_array = false; |
@@ -4101,15 +4105,55 @@ |
type_todo[i] = false; |
} |
+ // Elements_kind transition support. |
+ MapHandleList transition_target(maps->length()); |
+ // Collect possible transition targets. |
+ MapHandleList possible_transitioned_maps(maps->length()); |
for (int i = 0; i < maps->length(); ++i) { |
- ASSERT(maps->at(i)->IsMap()); |
- type_todo[maps->at(i)->elements_kind()] = true; |
- if (maps->at(i)->elements_kind() |
- >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
- todo_external_array = true; |
+ Handle<Map> map = maps->at(i); |
+ ElementsKind elements_kind = map->elements_kind(); |
+ if (elements_kind == FAST_DOUBLE_ELEMENTS || |
+ elements_kind == FAST_ELEMENTS) { |
+ possible_transitioned_maps.Add(map); |
} |
} |
+ // Get transition target for each map (NULL == no transition). |
+ for (int i = 0; i < maps->length(); ++i) { |
+ Handle<Map> map = maps->at(i); |
+ Handle<Map> transitioned_map = |
+ map->FindTransitionedMap(&possible_transitioned_maps); |
+ transition_target.Add(transitioned_map); |
+ } |
+ int num_untransitionable_maps = 0; |
+ Handle<Map> untransitionable_map; |
+ for (int i = 0; i < maps->length(); ++i) { |
+ Handle<Map> map = maps->at(i); |
+ ASSERT(map->IsMap()); |
+ if (!transition_target.at(i).is_null()) { |
+ object = AddInstruction(new(zone()) HTransitionElementsKind( |
+ object, map, transition_target.at(i))); |
+ } else { |
+ type_todo[map->elements_kind()] = true; |
+ if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
+ todo_external_array = true; |
+ } |
+ num_untransitionable_maps++; |
+ untransitionable_map = map; |
+ } |
+ } |
+ |
+ // If only one map is left after transitioning, handle this case |
+ // monomorphically. |
+ if (num_untransitionable_maps == 1) { |
+ HInstruction* instr = AddInstruction(BuildMonomorphicElementAccess( |
+ object, key, val, untransitionable_map, is_store)); |
+ *has_side_effects |= instr->HasSideEffects(); |
+ instr->set_position(position); |
+ return is_store ? NULL : instr; |
+ } |
+ |
+ AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
HBasicBlock* join = graph()->CreateBasicBlock(); |
HInstruction* elements_kind_instr = |
@@ -4241,7 +4285,9 @@ |
ASSERT(!expr->IsPropertyName()); |
HInstruction* instr = NULL; |
if (expr->IsMonomorphic()) { |
- instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store); |
+ Handle<Map> map = expr->GetMonomorphicReceiverType(); |
+ AddInstruction(new(zone()) HCheckNonSmi(obj)); |
+ instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); |
} else if (expr->GetReceiverTypes() != NULL && |
!expr->GetReceiverTypes()->is_empty()) { |
return HandlePolymorphicElementAccess( |
@@ -4269,7 +4315,7 @@ |
object, |
key, |
value, |
- function_strict_mode()); |
+ function_strict_mode_flag()); |
} |
bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
@@ -4511,7 +4557,7 @@ |
} |
-bool HGraphBuilder::TryInline(Call* expr) { |
+bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
if (!FLAG_use_inlining) return false; |
// The function call we are inlining is a method call if the call |
@@ -4539,9 +4585,9 @@ |
return false; |
} |
- CompilationInfo* outer_info = info(); |
#if !defined(V8_TARGET_ARCH_IA32) |
// Target must be able to use caller's context. |
+ CompilationInfo* outer_info = info(); |
if (target->context() != outer_info->closure()->context() || |
outer_info->scope()->contains_with() || |
outer_info->scope()->num_heap_slots() > 0) { |
@@ -4555,9 +4601,7 @@ |
HEnvironment* env = environment(); |
int current_level = 1; |
while (env->outer() != NULL) { |
- if (current_level == (FLAG_limit_inlining |
- ? Compiler::kMaxInliningLevels |
- : 2 * Compiler::kMaxInliningLevels)) { |
+ if (current_level == Compiler::kMaxInliningLevels) { |
TraceInline(target, caller, "inline depth limit reached"); |
return false; |
} |
@@ -4566,9 +4610,13 @@ |
} |
// Don't inline recursive functions. |
- if (*target_shared == outer_info->closure()->shared()) { |
- TraceInline(target, caller, "target is recursive"); |
- return false; |
+ for (FunctionState* state = function_state(); |
+ state != NULL; |
+ 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. |
@@ -4665,7 +4713,10 @@ |
Handle<Code>(target_shared->code()), |
Handle<Context>(target->context()->global_context()), |
isolate()); |
- FunctionState target_state(this, &target_info, &target_oracle); |
+ // The function state is new-allocated because we need to delete it |
+ // in two different places. |
+ FunctionState* target_state = |
+ new FunctionState(this, &target_info, &target_oracle, drop_extra); |
HConstant* undefined = graph()->GetConstantUndefined(); |
HEnvironment* inner_env = |
@@ -4699,6 +4750,7 @@ |
TraceInline(target, caller, "inline graph construction failed"); |
target_shared->DisableOptimization(*target); |
inline_bailout_ = true; |
+ delete target_state; |
return true; |
} |
@@ -4714,9 +4766,11 @@ |
ASSERT(function_return() != NULL); |
ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
if (call_context()->IsEffect()) { |
- current_block()->Goto(function_return()); |
+ current_block()->Goto(function_return(), drop_extra); |
} else { |
- current_block()->AddLeaveInlined(undefined, function_return()); |
+ current_block()->AddLeaveInlined(undefined, |
+ function_return(), |
+ drop_extra); |
} |
} else { |
// The graph builder assumes control can reach both branches of a |
@@ -4724,13 +4778,14 @@ |
// simply jumping to the false target. |
// |
// TODO(3168478): refactor to avoid this. |
+ ASSERT(call_context()->IsTest()); |
HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); |
current_block()->Finish(test); |
- empty_true->Goto(inlined_test_context()->if_true()); |
- empty_false->Goto(inlined_test_context()->if_false()); |
+ empty_true->Goto(inlined_test_context()->if_true(), drop_extra); |
+ empty_false->Goto(inlined_test_context()->if_false(), drop_extra); |
} |
} |
@@ -4742,19 +4797,21 @@ |
// Pop the return test context from the expression context stack. |
ASSERT(ast_context() == inlined_test_context()); |
ClearInlinedTestContext(); |
+ delete target_state; |
// Forward to the real test context. |
if (if_true->HasPredecessor()) { |
if_true->SetJoinId(expr->id()); |
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
- if_true->Goto(true_target); |
+ if_true->Goto(true_target, function_state()->drop_extra()); |
} |
if (if_false->HasPredecessor()) { |
if_false->SetJoinId(expr->id()); |
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
- if_false->Goto(false_target); |
+ if_false->Goto(false_target, function_state()->drop_extra()); |
} |
set_current_block(NULL); |
+ return true; |
} else if (function_return()->HasPredecessor()) { |
function_return()->SetJoinId(expr->id()); |
@@ -4762,7 +4819,7 @@ |
} else { |
set_current_block(NULL); |
} |
- |
+ delete target_state; |
return true; |
} |
@@ -5014,7 +5071,7 @@ |
// If there is a global property cell for the name at compile time and |
// access check is not enabled we assume that the function will not change |
// and generate optimized code for calling the function. |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
if (type == kUseCell && |
!info()->global_object()->IsAccessCheckNeeded()) { |
@@ -5069,32 +5126,17 @@ |
PushAndAdd(receiver); |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
- if (TryInline(expr)) { |
- // 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(); |
- } |
+ if (TryInline(expr, true)) { // Drop function from environment. |
return; |
} else { |
call = PreProcessCall(new(zone()) HInvokeFunction(context, |
function, |
argument_count)); |
+ call->set_position(expr->position()); |
+ AddInstruction(call); |
+ AddSimulate(expr->id()); |
Drop(1); // The function. |
+ return ast_context()->ReturnValue(call); |
} |
} else { |
@@ -5304,7 +5346,6 @@ |
void HGraphBuilder::VisitNot(UnaryOperation* expr) { |
- // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. |
if (ast_context()->IsTest()) { |
TestContext* context = TestContext::cast(ast_context()); |
VisitForControl(expr->expression(), |
@@ -5791,38 +5832,68 @@ |
void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, |
- Expression* sub_expr, |
+ HTypeof* typeof_expr, |
Handle<String> check) { |
- CHECK_ALIVE(VisitForTypeOf(sub_expr)); |
- HValue* value = Pop(); |
+ // Note: The HTypeof itself is removed during canonicalization, if possible. |
+ HValue* value = typeof_expr->value(); |
HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); |
instr->set_position(expr->position()); |
return ast_context()->ReturnControl(instr, expr->id()); |
} |
-bool HGraphBuilder::TryLiteralCompare(CompareOperation* expr) { |
- Expression *sub_expr; |
- Handle<String> check; |
- if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { |
- HandleLiteralCompareTypeof(expr, sub_expr, check); |
+static bool MatchLiteralCompareNil(HValue* left, |
+ Token::Value op, |
+ HValue* right, |
+ Handle<Object> nil, |
+ HValue** expr) { |
+ if (left->IsConstant() && |
+ HConstant::cast(left)->handle().is_identical_to(nil) && |
+ Token::IsEqualityOp(op)) { |
+ *expr = right; |
return true; |
} |
+ return false; |
+} |
- if (expr->IsLiteralCompareUndefined(&sub_expr)) { |
- HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); |
- return true; |
- } |
- if (expr->IsLiteralCompareNull(&sub_expr)) { |
- HandleLiteralCompareNil(expr, sub_expr, kNullValue); |
+static bool MatchLiteralCompareTypeof(HValue* left, |
+ Token::Value op, |
+ HValue* right, |
+ HTypeof** typeof_expr, |
+ Handle<String>* check) { |
+ if (left->IsTypeof() && |
+ Token::IsEqualityOp(op) && |
+ right->IsConstant() && |
+ HConstant::cast(right)->HasStringValue()) { |
+ *typeof_expr = HTypeof::cast(left); |
+ *check = Handle<String>::cast(HConstant::cast(right)->handle()); |
return true; |
} |
- |
return false; |
} |
+static bool IsLiteralCompareTypeof(HValue* left, |
+ Token::Value op, |
+ HValue* right, |
+ HTypeof** typeof_expr, |
+ Handle<String>* check) { |
+ return MatchLiteralCompareTypeof(left, op, right, typeof_expr, check) || |
+ MatchLiteralCompareTypeof(right, op, left, typeof_expr, check); |
+} |
+ |
+ |
+static bool IsLiteralCompareNil(HValue* left, |
+ Token::Value op, |
+ HValue* right, |
+ Handle<Object> nil, |
+ HValue** expr) { |
+ return MatchLiteralCompareNil(left, op, right, nil, expr) || |
+ MatchLiteralCompareNil(right, op, left, nil, expr); |
+} |
+ |
+ |
void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
ASSERT(!HasStackOverflow()); |
ASSERT(current_block() != NULL); |
@@ -5840,11 +5911,9 @@ |
return ast_context()->ReturnControl(instr, expr->id()); |
} |
- // Check for special cases that compare against literals. |
- if (TryLiteralCompare(expr)) return; |
- |
TypeInfo type_info = oracle()->CompareType(expr); |
// Check if this expression was ever executed according to type feedback. |
+ // Note that for the special typeof/null/undefined cases we get unknown here. |
if (type_info.IsUninitialized()) { |
AddInstruction(new(zone()) HSoftDeoptimize); |
current_block()->MarkAsDeoptimizing(); |
@@ -5859,6 +5928,20 @@ |
HValue* left = Pop(); |
Token::Value op = expr->op(); |
+ HTypeof* typeof_expr = NULL; |
+ Handle<String> check; |
+ if (IsLiteralCompareTypeof(left, op, right, &typeof_expr, &check)) { |
+ return HandleLiteralCompareTypeof(expr, typeof_expr, check); |
+ } |
+ HValue* sub_expr = NULL; |
+ Factory* f = graph()->isolate()->factory(); |
+ if (IsLiteralCompareNil(left, op, right, f->undefined_value(), &sub_expr)) { |
+ return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); |
+ } |
+ if (IsLiteralCompareNil(left, op, right, f->null_value(), &sub_expr)) { |
+ return HandleLiteralCompareNil(expr, sub_expr, kNullValue); |
+ } |
+ |
if (op == Token::INSTANCEOF) { |
// Check to see if the rhs of the instanceof is a global function not |
// residing in new space. If it is we assume that the function will stay the |
@@ -5871,7 +5954,7 @@ |
!info()->global_object()->IsAccessCheckNeeded()) { |
Handle<String> name = proxy->name(); |
Handle<GlobalObject> global(info()->global_object()); |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
global->Lookup(*name, &lookup); |
if (lookup.IsProperty() && |
lookup.type() == NORMAL && |
@@ -5947,13 +6030,11 @@ |
void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
- Expression* sub_expr, |
+ HValue* value, |
NilValue nil) { |
ASSERT(!HasStackOverflow()); |
ASSERT(current_block() != NULL); |
ASSERT(current_block()->HasPredecessor()); |
- CHECK_ALIVE(VisitForValue(sub_expr)); |
- HValue* value = Pop(); |
EqualityKind kind = |
expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality; |
HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil); |
@@ -5966,7 +6047,8 @@ |
ASSERT(!HasStackOverflow()); |
ASSERT(current_block() != NULL); |
ASSERT(current_block()->HasPredecessor()); |
- HThisFunction* self = new(zone()) HThisFunction; |
+ HThisFunction* self = new(zone()) HThisFunction( |
+ function_state()->compilation_info()->closure()); |
return ast_context()->ReturnInstruction(self, expr->id()); |
} |
@@ -5979,7 +6061,9 @@ |
void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, |
VariableMode mode, |
FunctionLiteral* function) { |
- if (mode == LET) return Bailout("unsupported let declaration"); |
+ if (mode == LET || mode == CONST_HARMONY) { |
+ return Bailout("unsupported harmony declaration"); |
+ } |
Variable* var = proxy->var(); |
switch (var->location()) { |
case Variable::UNALLOCATED: |