diff options
Diffstat (limited to 'deps/v8/src/hydrogen.cc')
-rw-r--r-- | deps/v8/src/hydrogen.cc | 437 |
1 files changed, 158 insertions, 279 deletions
diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 2d471cc29..c625fba8d 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -422,7 +422,7 @@ class ReachabilityAnalyzer BASE_EMBEDDED { }; -void HGraph::Verify(bool do_full_verify) const { +void HGraph::Verify() const { for (int i = 0; i < blocks_.length(); i++) { HBasicBlock* block = blocks_.at(i); @@ -473,27 +473,25 @@ void HGraph::Verify(bool do_full_verify) const { // Check special property of first block to have no predecessors. ASSERT(blocks_.at(0)->predecessors()->is_empty()); - if (do_full_verify) { - // Check that the graph is fully connected. - ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); - ASSERT(analyzer.visited_count() == blocks_.length()); + // Check that the graph is fully connected. + ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); + ASSERT(analyzer.visited_count() == blocks_.length()); - // Check that entry block dominator is NULL. - ASSERT(entry_block_->dominator() == NULL); + // Check that entry block dominator is NULL. + ASSERT(entry_block_->dominator() == NULL); - // Check dominators. - for (int i = 0; i < blocks_.length(); ++i) { - HBasicBlock* block = blocks_.at(i); - if (block->dominator() == NULL) { - // Only start block may have no dominator assigned to. - ASSERT(i == 0); - } else { - // Assert that block is unreachable if dominator must not be visited. - ReachabilityAnalyzer dominator_analyzer(entry_block_, - blocks_.length(), - block->dominator()); - ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id())); - } + // Check dominators. + for (int i = 0; i < blocks_.length(); ++i) { + HBasicBlock* block = blocks_.at(i); + if (block->dominator() == NULL) { + // Only start block may have no dominator assigned to. + ASSERT(i == 0); + } else { + // Assert that block is unreachable if dominator must not be visited. + ReachabilityAnalyzer dominator_analyzer(entry_block_, + blocks_.length(), + block->dominator()); + ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id())); } } } @@ -852,7 +850,7 @@ void HGraph::EliminateUnreachablePhis() { } -bool HGraph::CheckArgumentsPhiUses() { +bool HGraph::CheckPhis() { int block_count = blocks_.length(); for (int i = 0; i < block_count; ++i) { for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { @@ -865,11 +863,13 @@ bool HGraph::CheckArgumentsPhiUses() { } -bool HGraph::CheckConstPhiUses() { +bool HGraph::CollectPhis() { int block_count = blocks_.length(); + phi_list_ = new ZoneList<HPhi*>(block_count); for (int i = 0; i < block_count; ++i) { for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { HPhi* phi = blocks_[i]->phis()->at(j); + phi_list_->Add(phi); // Check for the hole value (from an uninitialized const). for (int k = 0; k < phi->OperandCount(); k++) { if (phi->OperandAt(k) == GetConstantHole()) return false; @@ -880,18 +880,6 @@ bool HGraph::CheckConstPhiUses() { } -void HGraph::CollectPhis() { - int block_count = blocks_.length(); - phi_list_ = new ZoneList<HPhi*>(block_count); - for (int i = 0; i < block_count; ++i) { - for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { - HPhi* phi = blocks_[i]->phis()->at(j); - phi_list_->Add(phi); - } - } -} - - void HGraph::InferTypes(ZoneList<HValue*>* worklist) { BitVector in_worklist(GetMaximumValueID()); for (int i = 0; i < worklist->length(); ++i) { @@ -1499,6 +1487,9 @@ int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( 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); } @@ -1860,7 +1851,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, } if (new_value == NULL) { - new_value = new(zone()) HChange(value, to, + new_value = new(zone()) HChange(value, value->representation(), to, is_truncating, deoptimize_on_undefined); } @@ -2311,7 +2302,7 @@ HGraph* HGraphBuilder::CreateGraph() { // Handle implicit declaration of the function name in named function // expressions before other declarations. if (scope->is_function_scope() && scope->function() != NULL) { - HandleDeclaration(scope->function(), CONST, NULL); + HandleDeclaration(scope->function(), Variable::CONST, NULL); } VisitDeclarations(scope->declarations()); AddSimulate(AstNode::kDeclarationsId); @@ -2332,24 +2323,17 @@ HGraph* HGraphBuilder::CreateGraph() { graph()->OrderBlocks(); graph()->AssignDominators(); - -#ifdef DEBUG - // Do a full verify after building the graph and computing dominators. - graph()->Verify(true); -#endif - graph()->PropagateDeoptimizingMark(); - if (!graph()->CheckConstPhiUses()) { - Bailout("Unsupported phi use of const variable"); - return NULL; - } graph()->EliminateRedundantPhis(); - if (!graph()->CheckArgumentsPhiUses()) { - Bailout("Unsupported phi use of arguments"); + if (!graph()->CheckPhis()) { + Bailout("Unsupported phi use of arguments object"); return NULL; } if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); - graph()->CollectPhis(); + if (!graph()->CollectPhis()) { + Bailout("Unsupported phi use of uninitialized constant"); + return NULL; + } HInferRepresentation rep(graph()); rep.Analyze(); @@ -3141,21 +3125,11 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); Variable* variable = expr->var(); - if (variable->mode() == LET) { + if (variable->mode() == Variable::LET) { return Bailout("reference to let variable"); } switch (variable->location()) { case Variable::UNALLOCATED: { - // Handle known global constants like 'undefined' specially to avoid a - // load from a global cell for them. - Handle<Object> constant_value = - isolate()->factory()->GlobalConstantFor(variable->name()); - if (!constant_value.is_null()) { - HConstant* instr = - new(zone()) HConstant(constant_value, Representation::Tagged()); - return ast_context()->ReturnInstruction(instr, expr->id()); - } - LookupResult lookup; GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false); @@ -3168,8 +3142,8 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { if (type == kUseCell) { Handle<GlobalObject> global(info()->global_object()); Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); - HLoadGlobalCell* instr = - new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails()); + bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); + HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); return ast_context()->ReturnInstruction(instr, expr->id()); } else { HValue* context = environment()->LookupContext(); @@ -3188,7 +3162,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { case Variable::PARAMETER: case Variable::LOCAL: { HValue* value = environment()->Lookup(variable); - if (variable->mode() == CONST && + if (variable->mode() == Variable::CONST && value == graph()->GetConstantHole()) { return Bailout("reference to uninitialized const variable"); } @@ -3196,7 +3170,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { } case Variable::CONTEXT: { - if (variable->mode() == CONST) { + if (variable->mode() == Variable::CONST) { return Bailout("reference to const context slot"); } HValue* context = BuildContextChainWalk(variable); @@ -3346,43 +3320,7 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { HValue* key = AddInstruction( new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), Representation::Integer32())); - HInstruction* elements_kind = - AddInstruction(new(zone()) HElementsKind(literal)); - HBasicBlock* store_fast = graph()->CreateBasicBlock(); - // Two empty blocks to satisfy edge split form. - HBasicBlock* store_fast_edgesplit1 = graph()->CreateBasicBlock(); - HBasicBlock* store_fast_edgesplit2 = graph()->CreateBasicBlock(); - HBasicBlock* store_generic = graph()->CreateBasicBlock(); - HBasicBlock* check_smi_only_elements = graph()->CreateBasicBlock(); - HBasicBlock* join = graph()->CreateBasicBlock(); - - HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(value); - smicheck->SetSuccessorAt(0, store_fast_edgesplit1); - smicheck->SetSuccessorAt(1, check_smi_only_elements); - current_block()->Finish(smicheck); - store_fast_edgesplit1->Finish(new(zone()) HGoto(store_fast)); - - set_current_block(check_smi_only_elements); - HCompareConstantEqAndBranch* smi_elements_check = - new(zone()) HCompareConstantEqAndBranch(elements_kind, - FAST_SMI_ONLY_ELEMENTS, - Token::EQ_STRICT); - smi_elements_check->SetSuccessorAt(0, store_generic); - smi_elements_check->SetSuccessorAt(1, store_fast_edgesplit2); - current_block()->Finish(smi_elements_check); - store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast)); - - set_current_block(store_fast); AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); - store_fast->Goto(join); - - set_current_block(store_generic); - AddInstruction(BuildStoreKeyedGeneric(literal, key, value)); - store_generic->Goto(join); - - join->SetJoinId(expr->id()); - set_current_block(join); - AddSimulate(expr->GetIdForElement(i)); } return ast_context()->ReturnValue(Pop()); @@ -3626,10 +3564,10 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, LookupResult lookup; GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); if (type == kUseCell) { + bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); Handle<GlobalObject> global(info()->global_object()); Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); - HInstruction* instr = - new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails()); + HInstruction* instr = new(zone()) HStoreGlobalCell(value, cell, check_hole); instr->set_position(position); AddInstruction(instr); if (instr->HasSideEffects()) AddSimulate(ast_id); @@ -3663,7 +3601,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { if (proxy != NULL) { Variable* var = proxy->var(); - if (var->mode() == CONST || var->mode() == LET) { + if (var->mode() == Variable::CONST || var->mode() == Variable::LET) { return Bailout("unsupported let or const compound assignment"); } @@ -3808,7 +3746,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { HandlePropertyAssignment(expr); } else if (proxy != NULL) { Variable* var = proxy->var(); - if (var->mode() == CONST) { + if (var->mode() == Variable::CONST) { if (expr->op() != Token::INIT_CONST) { return Bailout("non-initializer assignment to const"); } @@ -3819,7 +3757,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { // variables (e.g. initialization inside a loop). HValue* old_value = environment()->Lookup(var); AddInstruction(new HUseConst(old_value)); - } else if (var->mode() == LET) { + } else if (var->mode() == Variable::LET) { return Bailout("unsupported assignment to let"); } @@ -3847,7 +3785,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { } case Variable::CONTEXT: { - ASSERT(var->mode() != CONST); + ASSERT(var->mode() != Variable::CONST); // Bail out if we try to mutate a parameter value in a function using // the arguments object. We do not (yet) correctly handle the // arguments property of the function. @@ -3993,7 +3931,6 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS: break; - case FAST_SMI_ONLY_ELEMENTS: case FAST_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: @@ -4010,30 +3947,6 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( } -HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, - HValue* checked_key, - HValue* val, - ElementsKind elements_kind, - bool is_store) { - if (is_store) { - ASSERT(val != NULL); - if (elements_kind == FAST_DOUBLE_ELEMENTS) { - return new(zone()) HStoreKeyedFastDoubleElement( - elements, checked_key, val); - } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. - return new(zone()) HStoreKeyedFastElement( - elements, checked_key, val, elements_kind); - } - } - // It's an element load (!is_store). - if (elements_kind == FAST_DOUBLE_ELEMENTS) { - return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); - } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. - return new(zone()) HLoadKeyedFastElement(elements, checked_key); - } -} - - HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, HValue* key, HValue* val, @@ -4041,20 +3954,17 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, 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(); - bool fast_double_elements = map->has_fast_double_elements(); - if (!fast_smi_only_elements && - !fast_elements && - !fast_double_elements && + if (!map->has_fast_elements() && + !map->has_fast_double_elements() && !map->has_external_array_elements()) { return is_store ? BuildStoreKeyedGeneric(object, key, val) : BuildLoadKeyedGeneric(object, key); } + AddInstruction(new(zone()) HCheckNonSmi(object)); + HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); - if (is_store && (fast_elements || fast_smi_only_elements)) { + bool fast_double_elements = map->has_fast_double_elements(); + if (is_store && map->has_fast_elements()) { AddInstruction(new(zone()) HCheckMap( elements, isolate()->factory()->fixed_array_map())); } @@ -4069,15 +3979,28 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, return BuildExternalArrayElementAccess(external_elements, checked_key, val, map->elements_kind(), is_store); } - ASSERT(fast_smi_only_elements || fast_elements || fast_double_elements); + ASSERT(map->has_fast_elements() || fast_double_elements); if (map->instance_type() == JS_ARRAY_TYPE) { length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); } else { length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); } checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); - return BuildFastElementAccess(elements, checked_key, val, - map->elements_kind(), is_store); + if (is_store) { + if (fast_double_elements) { + return new(zone()) HStoreKeyedFastDoubleElement(elements, + checked_key, + val); + } else { + return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); + } + } else { + if (fast_double_elements) { + return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); + } else { + return new(zone()) HLoadKeyedFastElement(elements, checked_key); + } + } } @@ -4119,20 +4042,14 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, HLoadExternalArrayPointer* external_elements = NULL; HInstruction* checked_key = NULL; - // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, - // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external - // arrays. - STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); - STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); - STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); - STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); + // FAST_ELEMENTS is assumed to be the first case. + STATIC_ASSERT(FAST_ELEMENTS == 0); - for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; + for (ElementsKind elements_kind = FAST_ELEMENTS; elements_kind <= LAST_ELEMENTS_KIND; elements_kind = ElementsKind(elements_kind + 1)) { - // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS, - // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code - // that's executed for all external array cases. + // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we + // need to add some code that's executed for all external array cases. STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == LAST_ELEMENTS_KIND); if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND @@ -4154,25 +4071,15 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, set_current_block(if_true); HInstruction* access; - if (elements_kind == FAST_SMI_ONLY_ELEMENTS || - elements_kind == FAST_ELEMENTS || + if (elements_kind == FAST_ELEMENTS || elements_kind == FAST_DOUBLE_ELEMENTS) { - if (is_store && elements_kind == FAST_SMI_ONLY_ELEMENTS) { - AddInstruction(new(zone()) HCheckSmi(val)); - } - if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { + bool fast_double_elements = + elements_kind == FAST_DOUBLE_ELEMENTS; + if (is_store && elements_kind == FAST_ELEMENTS) { AddInstruction(new(zone()) HCheckMap( elements, isolate()->factory()->fixed_array_map(), elements_kind_branch)); } - // TODO(jkummerow): The need for these two blocks could be avoided - // in one of two ways: - // (1) Introduce ElementsKinds for JSArrays that are distinct from - // those for fast objects. - // (2) Put the common instructions into a third "join" block. This - // requires additional AST IDs that we can deopt to from inside - // that join block. They must be added to the Property class (when - // it's a keyed property) and registered in the full codegen. HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); HHasInstanceTypeAndBranch* typecheck = @@ -4182,15 +4089,29 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, current_block()->Finish(typecheck); set_current_block(if_jsarray); - HInstruction* length; - length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck)); + HInstruction* length = new(zone()) HJSArrayLength(object, typecheck); + AddInstruction(length); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); - access = AddInstruction(BuildFastElementAccess( - elements, checked_key, val, elements_kind, is_store)); - if (!is_store) { + if (is_store) { + if (fast_double_elements) { + access = AddInstruction( + new(zone()) HStoreKeyedFastDoubleElement(elements, + checked_key, + val)); + } else { + access = AddInstruction( + new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); + } + } else { + if (fast_double_elements) { + access = AddInstruction( + new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); + } else { + access = AddInstruction( + new(zone()) HLoadKeyedFastElement(elements, checked_key)); + } Push(access); } - *has_side_effects |= access->HasSideEffects(); if (position != -1) { access->set_position(position); @@ -4200,8 +4121,25 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, set_current_block(if_fastobject); length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); - access = AddInstruction(BuildFastElementAccess( - elements, checked_key, val, elements_kind, is_store)); + if (is_store) { + if (fast_double_elements) { + access = AddInstruction( + new(zone()) HStoreKeyedFastDoubleElement(elements, + checked_key, + val)); + } else { + access = AddInstruction( + new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); + } + } else { + if (fast_double_elements) { + access = AddInstruction( + new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); + } else { + access = AddInstruction( + new(zone()) HLoadKeyedFastElement(elements, checked_key)); + } + } } else if (elements_kind == DICTIONARY_ELEMENTS) { if (is_store) { access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); @@ -4539,25 +4477,20 @@ bool HGraphBuilder::TryInline(Call* expr) { return false; } + // No context change required. CompilationInfo* outer_info = info(); -#if !defined(V8_TARGET_ARCH_IA32) - // Target must be able to use caller's context. if (target->context() != outer_info->closure()->context() || outer_info->scope()->contains_with() || outer_info->scope()->num_heap_slots() > 0) { TraceInline(target, caller, "target requires context change"); return false; } -#endif - // Don't inline deeper than kMaxInliningLevels calls. 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; } @@ -4663,8 +4596,7 @@ bool HGraphBuilder::TryInline(Call* expr) { ASSERT(target_shared->has_deoptimization_support()); TypeFeedbackOracle target_oracle( Handle<Code>(target_shared->code()), - Handle<Context>(target->context()->global_context()), - isolate()); + Handle<Context>(target->context()->global_context())); FunctionState target_state(this, &target_info, &target_oracle); HConstant* undefined = graph()->GetConstantUndefined(); @@ -4673,17 +4605,6 @@ bool HGraphBuilder::TryInline(Call* expr) { function, undefined, call_kind); -#ifdef V8_TARGET_ARCH_IA32 - // IA32 only, overwrite the caller's context in the deoptimization - // environment with the correct one. - // - // TODO(kmillikin): implement the same inlining on other platforms so we - // can remove the unsightly ifdefs in this function. - HConstant* context = new HConstant(Handle<Context>(target->context()), - Representation::Tagged()); - AddInstruction(context); - inner_env->BindContext(context); -#endif HBasicBlock* body_entry = CreateBasicBlock(inner_env); current_block()->Goto(body_entry); body_entry->SetJoinId(expr->ReturnId()); @@ -5004,8 +4925,8 @@ void HGraphBuilder::VisitCall(Call* expr) { } } else { - expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); VariableProxy* proxy = expr->expression()->AsVariableProxy(); + // FIXME. bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); if (global_call) { @@ -5057,46 +4978,6 @@ void HGraphBuilder::VisitCall(Call* expr) { Drop(argument_count); } - } else if (expr->IsMonomorphic()) { - // The function is on the stack in the unoptimized code during - // evaluation of the arguments. - CHECK_ALIVE(VisitForValue(expr->expression())); - HValue* function = Top(); - HValue* context = environment()->LookupContext(); - HGlobalObject* global = new(zone()) HGlobalObject(context); - HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); - AddInstruction(global); - 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(); - } - return; - } else { - call = PreProcessCall(new(zone()) HInvokeFunction(context, - function, - argument_count)); - Drop(1); // The function. - } - } else { CHECK_ALIVE(VisitArgument(expr->expression())); HValue* context = environment()->LookupContext(); @@ -5403,7 +5284,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { if (proxy != NULL) { Variable* var = proxy->var(); - if (var->mode() == CONST) { + if (var->mode() == Variable::CONST) { return Bailout("unsupported count operation with const"); } // Argument of the count operation is a variable, not a property. @@ -5790,36 +5671,26 @@ Representation HGraphBuilder::ToRepresentation(TypeInfo info) { } -void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, - Expression* sub_expr, +void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* compare_expr, + Expression* expr, Handle<String> check) { - CHECK_ALIVE(VisitForTypeOf(sub_expr)); - HValue* value = Pop(); - HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); - instr->set_position(expr->position()); - return ast_context()->ReturnControl(instr, expr->id()); + CHECK_ALIVE(VisitForTypeOf(expr)); + HValue* expr_value = Pop(); + HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(expr_value, check); + instr->set_position(compare_expr->position()); + return ast_context()->ReturnControl(instr, compare_expr->id()); } -bool HGraphBuilder::TryLiteralCompare(CompareOperation* expr) { - Expression *sub_expr; - Handle<String> check; - if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { - HandleLiteralCompareTypeof(expr, sub_expr, check); - return true; - } - - if (expr->IsLiteralCompareUndefined(&sub_expr)) { - HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); - return true; - } - - if (expr->IsLiteralCompareNull(&sub_expr)) { - HandleLiteralCompareNil(expr, sub_expr, kNullValue); - return true; - } - - return false; +void HGraphBuilder::HandleLiteralCompareUndefined( + CompareOperation* compare_expr, Expression* expr) { + CHECK_ALIVE(VisitForValue(expr)); + HValue* lhs = Pop(); + HValue* rhs = graph()->GetConstantUndefined(); + HCompareObjectEqAndBranch* instr = + new(zone()) HCompareObjectEqAndBranch(lhs, rhs); + instr->set_position(compare_expr->position()); + return ast_context()->ReturnControl(instr, compare_expr->id()); } @@ -5841,7 +5712,17 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { } // Check for special cases that compare against literals. - if (TryLiteralCompare(expr)) return; + Expression *sub_expr; + Handle<String> check; + if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { + HandleLiteralCompareTypeof(expr, sub_expr, check); + return; + } + + if (expr->IsLiteralCompareUndefined(&sub_expr)) { + HandleLiteralCompareUndefined(expr, sub_expr); + return; + } TypeInfo type_info = oracle()->CompareType(expr); // Check if this expression was ever executed according to type feedback. @@ -5946,18 +5827,14 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { } -void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, - Expression* sub_expr, - NilValue nil) { +void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - CHECK_ALIVE(VisitForValue(sub_expr)); + CHECK_ALIVE(VisitForValue(expr->expression())); HValue* value = Pop(); - EqualityKind kind = - expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality; - HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil); - instr->set_position(expr->position()); + HIsNullAndBranch* instr = + new(zone()) HIsNullAndBranch(value, expr->is_strict()); return ast_context()->ReturnControl(instr, expr->id()); } @@ -5977,9 +5854,9 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) { void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, - VariableMode mode, + Variable::Mode mode, FunctionLiteral* function) { - if (mode == LET) return Bailout("unsupported let declaration"); + if (mode == Variable::LET) return Bailout("unsupported let declaration"); Variable* var = proxy->var(); switch (var->location()) { case Variable::UNALLOCATED: @@ -5987,9 +5864,9 @@ void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, case Variable::PARAMETER: case Variable::LOCAL: case Variable::CONTEXT: - if (mode == CONST || function != NULL) { + if (mode == Variable::CONST || function != NULL) { HValue* value = NULL; - if (mode == CONST) { + if (mode == Variable::CONST) { value = graph()->GetConstantHole(); } else { VisitForValue(function); @@ -6040,7 +5917,9 @@ void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); HValue* value = Pop(); HHasInstanceTypeAndBranch* result = - new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE); + new(zone()) HHasInstanceTypeAndBranch(value, + JS_FUNCTION_TYPE, + JS_FUNCTION_PROXY_TYPE); return ast_context()->ReturnControl(result, call->id()); } @@ -6940,7 +6819,7 @@ void HPhase::End() const { } #ifdef DEBUG - if (graph_ != NULL) graph_->Verify(false); // No full verify. + if (graph_ != NULL) graph_->Verify(); if (allocator_ != NULL) allocator_->Verify(); #endif } |