| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 837c9780c50abe3753ddfd8c86d60a45626405f8..7ec65df28ddcf9d3d6866473dbfb5226f0359475 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -957,9 +957,8 @@ void HGraphBuilder::LoopBuilder::EndBody() {
|
|
|
| // Push the new increment value on the expression stack to merge into the phi.
|
| builder_->environment()->Push(increment_);
|
| - HBasicBlock* last_block = builder_->current_block();
|
| - last_block->GotoNoSimulate(header_block_);
|
| - header_block_->loop_information()->RegisterBackEdge(last_block);
|
| + builder_->current_block()->GotoNoSimulate(header_block_);
|
| + header_block_->loop_information()->RegisterBackEdge(body_block_);
|
|
|
| builder_->set_current_block(exit_block_);
|
| // Pop the phi from the expression stack
|
| @@ -1050,14 +1049,12 @@ void HGraphBuilder::PadEnvironmentForContinuation(
|
| HBasicBlock* continuation) {
|
| if (continuation->last_environment() != NULL) {
|
| // When merging from a deopt block to a continuation, resolve differences in
|
| - // environment by pushing constant 0 and popping extra values so that the
|
| - // environments match during the join. Push 0 since it has the most specific
|
| - // representation, and will not influence representation inference of the
|
| - // phi.
|
| + // environment by pushing undefined and popping extra values so that the
|
| + // environments match during the join.
|
| int continuation_env_length = continuation->last_environment()->length();
|
| while (continuation_env_length != from->last_environment()->length()) {
|
| if (continuation_env_length > from->last_environment()->length()) {
|
| - from->last_environment()->Push(graph()->GetConstant0());
|
| + from->last_environment()->Push(graph()->GetConstantUndefined());
|
| } else {
|
| from->last_environment()->Pop();
|
| }
|
| @@ -1719,6 +1716,38 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
|
| }
|
|
|
|
|
| +HInstruction* HGraphBuilder::BuildUnaryMathOp(
|
| + HValue* input, Handle<Type> type, Token::Value operation) {
|
| + // We only handle the numeric cases here
|
| + type = handle(
|
| + Type::Intersect(type, handle(Type::Number(), isolate())), isolate());
|
| +
|
| + switch (operation) {
|
| + default:
|
| + UNREACHABLE();
|
| + case Token::SUB: {
|
| + HInstruction* instr =
|
| + NewUncasted<HMul>(input, graph()->GetConstantMinus1());
|
| + Representation rep = Representation::FromType(type);
|
| + if (type->Is(Type::None())) {
|
| + Add<HDeoptimize>(Deoptimizer::SOFT);
|
| + }
|
| + if (instr->IsBinaryOperation()) {
|
| + HBinaryOperation* binop = HBinaryOperation::cast(instr);
|
| + binop->set_observed_input_representation(1, rep);
|
| + binop->set_observed_input_representation(2, rep);
|
| + }
|
| + return instr;
|
| + }
|
| + case Token::BIT_NOT:
|
| + if (type->Is(Type::None())) {
|
| + Add<HDeoptimize>(Deoptimizer::SOFT);
|
| + }
|
| + return New<HBitNot>(input);
|
| + }
|
| +}
|
| +
|
| +
|
| void HGraphBuilder::BuildCompareNil(
|
| HValue* value,
|
| Handle<Type> type,
|
| @@ -2549,7 +2578,7 @@ void ValueContext::ReturnValue(HValue* value) {
|
| // The value is tracked in the bailout environment, and communicated
|
| // through the environment as the result of the expression.
|
| if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
|
| - owner()->Bailout(kBadValueContextForArgumentsValue);
|
| + owner()->Bailout("bad value context for arguments value");
|
| }
|
| owner()->Push(value);
|
| }
|
| @@ -2601,7 +2630,7 @@ void EffectContext::ReturnContinuation(HIfContinuation* continuation,
|
| void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
|
| ASSERT(!instr->IsControlInstruction());
|
| if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
|
| - return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
|
| + return owner()->Bailout("bad value context for arguments object value");
|
| }
|
| owner()->AddInstruction(instr);
|
| owner()->Push(instr);
|
| @@ -2614,7 +2643,7 @@ void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
|
| void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
|
| ASSERT(!instr->HasObservableSideEffects());
|
| if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
|
| - return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
|
| + return owner()->Bailout("bad value context for arguments object value");
|
| }
|
| HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
|
| HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
|
| @@ -2704,7 +2733,7 @@ void TestContext::BuildBranch(HValue* value) {
|
| // branch.
|
| HOptimizedGraphBuilder* builder = owner();
|
| if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
|
| - builder->Bailout(kArgumentsObjectValueInATestContext);
|
| + builder->Bailout("arguments object value in a test context");
|
| }
|
| if (value->IsConstant()) {
|
| HConstant* constant_value = HConstant::cast(value);
|
| @@ -2750,7 +2779,7 @@ void TestContext::BuildBranch(HValue* value) {
|
| } while (false)
|
|
|
|
|
| -void HOptimizedGraphBuilder::Bailout(BailoutReason reason) {
|
| +void HOptimizedGraphBuilder::Bailout(const char* reason) {
|
| current_info()->set_bailout_reason(reason);
|
| SetStackOverflow();
|
| }
|
| @@ -2809,16 +2838,16 @@ void HOptimizedGraphBuilder::VisitExpressions(
|
|
|
| bool HOptimizedGraphBuilder::BuildGraph() {
|
| if (current_info()->function()->is_generator()) {
|
| - Bailout(kFunctionIsAGenerator);
|
| + Bailout("function is a generator");
|
| return false;
|
| }
|
| Scope* scope = current_info()->scope();
|
| if (scope->HasIllegalRedeclaration()) {
|
| - Bailout(kFunctionWithIllegalRedeclaration);
|
| + Bailout("function with illegal redeclaration");
|
| return false;
|
| }
|
| if (scope->calls_eval()) {
|
| - Bailout(kFunctionCallsEval);
|
| + Bailout("function calls eval");
|
| return false;
|
| }
|
| SetUpScope(scope);
|
| @@ -2884,7 +2913,8 @@ bool HOptimizedGraphBuilder::BuildGraph() {
|
| }
|
|
|
|
|
| -bool HGraph::Optimize(BailoutReason* bailout_reason) {
|
| +bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
|
| + *bailout_reason = SmartArrayPointer<char>();
|
| OrderBlocks();
|
| AssignDominators();
|
|
|
| @@ -2905,12 +2935,14 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
|
|
|
| Run<HPropagateDeoptimizingMarkPhase>();
|
| if (!CheckConstPhiUses()) {
|
| - *bailout_reason = kUnsupportedPhiUseOfConstVariable;
|
| + *bailout_reason = SmartArrayPointer<char>(StrDup(
|
| + "Unsupported phi use of const variable"));
|
| return false;
|
| }
|
| Run<HRedundantPhiEliminationPhase>();
|
| if (!CheckArgumentsPhiUses()) {
|
| - *bailout_reason = kUnsupportedPhiUseOfArguments;
|
| + *bailout_reason = SmartArrayPointer<char>(StrDup(
|
| + "Unsupported phi use of arguments"));
|
| return false;
|
| }
|
|
|
| @@ -2950,10 +2982,11 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
|
| // Eliminate redundant stack checks on backwards branches.
|
| Run<HStackCheckEliminationPhase>();
|
|
|
| - if (FLAG_array_bounds_checks_elimination) {
|
| + if (FLAG_idefs) SetupInformativeDefinitions();
|
| + if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) {
|
| Run<HBoundsCheckEliminationPhase>();
|
| }
|
| - if (FLAG_array_bounds_checks_hoisting) {
|
| + if (FLAG_array_bounds_checks_hoisting && !FLAG_idefs) {
|
| Run<HBoundsCheckHoistingPhase>();
|
| }
|
| if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
|
| @@ -2965,6 +2998,50 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
|
| }
|
|
|
|
|
| +void HGraph::SetupInformativeDefinitionsInBlock(HBasicBlock* block) {
|
| + for (int phi_index = 0; phi_index < block->phis()->length(); phi_index++) {
|
| + HPhi* phi = block->phis()->at(phi_index);
|
| + phi->AddInformativeDefinitions();
|
| + phi->SetFlag(HValue::kIDefsProcessingDone);
|
| + // We do not support phis that "redefine just one operand".
|
| + ASSERT(!phi->IsInformativeDefinition());
|
| + }
|
| +
|
| + for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
|
| + HInstruction* i = it.Current();
|
| + i->AddInformativeDefinitions();
|
| + i->SetFlag(HValue::kIDefsProcessingDone);
|
| + i->UpdateRedefinedUsesWhileSettingUpInformativeDefinitions();
|
| + }
|
| +}
|
| +
|
| +
|
| +// This method is recursive, so if its stack frame is large it could
|
| +// cause a stack overflow.
|
| +// To keep the individual stack frames small we do the actual work inside
|
| +// SetupInformativeDefinitionsInBlock();
|
| +void HGraph::SetupInformativeDefinitionsRecursively(HBasicBlock* block) {
|
| + SetupInformativeDefinitionsInBlock(block);
|
| + for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
|
| + SetupInformativeDefinitionsRecursively(block->dominated_blocks()->at(i));
|
| + }
|
| +
|
| + for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
|
| + HInstruction* i = it.Current();
|
| + if (i->IsBoundsCheck()) {
|
| + HBoundsCheck* check = HBoundsCheck::cast(i);
|
| + check->ApplyIndexChange();
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void HGraph::SetupInformativeDefinitions() {
|
| + HPhase phase("H_Setup informative definitions", this);
|
| + SetupInformativeDefinitionsRecursively(entry_block());
|
| +}
|
| +
|
| +
|
| void HGraph::RestoreActualValues() {
|
| HPhase phase("H_Restore actual values", this);
|
|
|
| @@ -3047,7 +3124,7 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
|
| // not have declarations).
|
| if (scope->arguments() != NULL) {
|
| if (!scope->arguments()->IsStackAllocated()) {
|
| - return Bailout(kContextAllocatedArguments);
|
| + return Bailout("context-allocated arguments");
|
| }
|
|
|
| environment()->Bind(scope->arguments(),
|
| @@ -3068,7 +3145,7 @@ void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| if (stmt->scope() != NULL) {
|
| - return Bailout(kScopedBlock);
|
| + return Bailout("ScopedBlock");
|
| }
|
| BreakAndContinueInfo break_info(stmt);
|
| { BreakAndContinueScope push(&break_info, this);
|
| @@ -3280,7 +3357,7 @@ void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - return Bailout(kWithStatement);
|
| + return Bailout("WithStatement");
|
| }
|
|
|
|
|
| @@ -3295,12 +3372,12 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
| ZoneList<CaseClause*>* clauses = stmt->cases();
|
| int clause_count = clauses->length();
|
| if (clause_count > kCaseClauseLimit) {
|
| - return Bailout(kSwitchStatementTooManyClauses);
|
| + return Bailout("SwitchStatement: too many clauses");
|
| }
|
|
|
| ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH);
|
| if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) {
|
| - return Bailout(kSwitchStatementMixedOrNonLiteralSwitchLabels);
|
| + return Bailout("SwitchStatement: mixed or non-literal switch labels");
|
| }
|
|
|
| HValue* context = environment()->context();
|
| @@ -3592,16 +3669,16 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
|
| ASSERT(current_block()->HasPredecessor());
|
|
|
| if (!FLAG_optimize_for_in) {
|
| - return Bailout(kForInStatementOptimizationIsDisabled);
|
| + return Bailout("ForInStatement optimization is disabled");
|
| }
|
|
|
| if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) {
|
| - return Bailout(kForInStatementIsNotFastCase);
|
| + return Bailout("ForInStatement is not fast case");
|
| }
|
|
|
| if (!stmt->each()->IsVariableProxy() ||
|
| !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
|
| - return Bailout(kForInStatementWithNonLocalEachVariable);
|
| + return Bailout("ForInStatement with non-local each variable");
|
| }
|
|
|
| Variable* each_var = stmt->each()->AsVariableProxy()->var();
|
| @@ -3695,7 +3772,7 @@ void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - return Bailout(kForOfStatement);
|
| + return Bailout("ForOfStatement");
|
| }
|
|
|
|
|
| @@ -3703,7 +3780,7 @@ void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - return Bailout(kTryCatchStatement);
|
| + return Bailout("TryCatchStatement");
|
| }
|
|
|
|
|
| @@ -3712,7 +3789,7 @@ void HOptimizedGraphBuilder::VisitTryFinallyStatement(
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - return Bailout(kTryFinallyStatement);
|
| + return Bailout("TryFinallyStatement");
|
| }
|
|
|
|
|
| @@ -3720,7 +3797,7 @@ void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - return Bailout(kDebuggerStatement);
|
| + return Bailout("DebuggerStatement");
|
| }
|
|
|
|
|
| @@ -3766,7 +3843,7 @@ void HOptimizedGraphBuilder::VisitSharedFunctionInfoLiteral(
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - return Bailout(kSharedFunctionInfoLiteral);
|
| + return Bailout("SharedFunctionInfoLiteral");
|
| }
|
|
|
|
|
| @@ -3846,7 +3923,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
| case Variable::UNALLOCATED: {
|
| if (IsLexicalVariableMode(variable->mode())) {
|
| // TODO(rossberg): should this be an ASSERT?
|
| - return Bailout(kReferenceToGlobalLexicalVariable);
|
| + return Bailout("reference to global lexical variable");
|
| }
|
| // Handle known global constants like 'undefined' specially to avoid a
|
| // load from a global cell for them.
|
| @@ -3903,7 +3980,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
| if (value == graph()->GetConstantHole()) {
|
| ASSERT(IsDeclaredVariableMode(variable->mode()) &&
|
| variable->mode() != VAR);
|
| - return Bailout(kReferenceToUninitializedVariable);
|
| + return Bailout("reference to uninitialized variable");
|
| }
|
| return ast_context()->ReturnValue(value);
|
| }
|
| @@ -3915,7 +3992,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
| }
|
|
|
| case Variable::LOOKUP:
|
| - return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
|
| + return Bailout("reference to a variable which requires dynamic lookup");
|
| }
|
| }
|
|
|
| @@ -4036,7 +4113,8 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
|
| int* data_size,
|
| int* pointer_size) {
|
| if (boilerplate->map()->is_deprecated()) {
|
| - Handle<Object> result = JSObject::TryMigrateInstance(boilerplate);
|
| + Handle<Object> result =
|
| + JSObject::TryMigrateInstance(boilerplate);
|
| if (result->IsSmi()) return false;
|
| }
|
|
|
| @@ -4213,7 +4291,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
| case ObjectLiteral::Property::PROTOTYPE:
|
| case ObjectLiteral::Property::SETTER:
|
| case ObjectLiteral::Property::GETTER:
|
| - return Bailout(kObjectLiteralWithComplexProperty);
|
| + return Bailout("Object literal with complex property");
|
| default: UNREACHABLE();
|
| }
|
| }
|
| @@ -4252,7 +4330,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
| raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
|
| isolate(), literals, expr->constant_elements());
|
| if (raw_boilerplate.is_null()) {
|
| - return Bailout(kArrayBoilerplateCreationFailed);
|
| + return Bailout("array boilerplate creation failed");
|
| }
|
|
|
| site = isolate()->factory()->NewAllocationSite();
|
| @@ -4343,7 +4421,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
|
|
| CHECK_ALIVE(VisitForValue(subexpr));
|
| HValue* value = Pop();
|
| - if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral);
|
| + if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal");
|
|
|
| elements = AddLoadElements(literal);
|
|
|
| @@ -4423,7 +4501,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
|
| if (proto_result.IsProperty()) {
|
| // If the inherited property could induce readonly-ness, bail out.
|
| if (proto_result.IsReadOnly() || !proto_result.IsCacheable()) {
|
| - Bailout(kImproperObjectOnPrototypeChainForStore);
|
| + Bailout("improper object on prototype chain for store");
|
| return NULL;
|
| }
|
| // We only need to check up to the preexisting property.
|
| @@ -4436,9 +4514,9 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
|
| ASSERT(proto->GetPrototype(isolate())->IsNull());
|
| }
|
| ASSERT(proto->IsJSObject());
|
| - BuildCheckPrototypeMaps(
|
| + Add<HCheckPrototypeMaps>(
|
| Handle<JSObject>(JSObject::cast(map->prototype())),
|
| - Handle<JSObject>(JSObject::cast(proto)));
|
| + Handle<JSObject>(JSObject::cast(proto)), top_info());
|
| }
|
|
|
| HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name);
|
| @@ -4476,8 +4554,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
|
|
|
| if (transition_to_field) {
|
| Handle<Map> transition(lookup->GetTransitionMapFromMap(*map));
|
| - HConstant* transition_constant = Add<HConstant>(transition);
|
| - instr->SetTransition(transition_constant, top_info());
|
| + instr->SetTransition(transition, top_info());
|
| // TODO(fschneider): Record the new map type of the object in the IR to
|
| // enable elimination of redundant checks after the transition store.
|
| instr->SetGVNFlag(kChangesMaps);
|
| @@ -4593,7 +4670,8 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic(
|
|
|
| Handle<JSObject> holder(lookup.holder());
|
| Handle<Map> holder_map(holder->map());
|
| - BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype), holder);
|
| + Add<HCheckPrototypeMaps>(
|
| + Handle<JSObject>::cast(prototype), holder, top_info());
|
| HValue* holder_value = Add<HConstant>(holder);
|
| return BuildLoadNamedField(holder_value,
|
| HObjectAccess::ForField(holder_map, &lookup, name));
|
| @@ -4927,7 +5005,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| if (proxy != NULL) {
|
| Variable* var = proxy->var();
|
| if (var->mode() == LET) {
|
| - return Bailout(kUnsupportedLetCompoundAssignment);
|
| + return Bailout("unsupported let compound assignment");
|
| }
|
|
|
| CHECK_ALIVE(VisitForValue(operation));
|
| @@ -4943,7 +5021,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| case Variable::PARAMETER:
|
| case Variable::LOCAL:
|
| if (var->mode() == CONST) {
|
| - return Bailout(kUnsupportedConstCompoundAssignment);
|
| + return Bailout("unsupported const compound assignment");
|
| }
|
| BindIfLive(var, Top());
|
| break;
|
| @@ -4959,7 +5037,8 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| int count = current_info()->scope()->num_parameters();
|
| for (int i = 0; i < count; ++i) {
|
| if (var == current_info()->scope()->parameter(i)) {
|
| - Bailout(kAssignmentToParameterFunctionUsesArgumentsObject);
|
| + Bailout(
|
| + "assignment to parameter, function uses arguments object");
|
| }
|
| }
|
| }
|
| @@ -4990,7 +5069,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| }
|
|
|
| case Variable::LOOKUP:
|
| - return Bailout(kCompoundAssignmentToLookupSlot);
|
| + return Bailout("compound assignment to lookup slot");
|
| }
|
| return ast_context()->ReturnValue(Pop());
|
|
|
| @@ -5079,7 +5158,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| }
|
|
|
| } else {
|
| - return Bailout(kInvalidLhsInCompoundAssignment);
|
| + return Bailout("invalid lhs in compound assignment");
|
| }
|
| }
|
|
|
| @@ -5116,11 +5195,11 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
|
| }
|
| } else if (var->mode() == CONST_HARMONY) {
|
| if (expr->op() != Token::INIT_CONST_HARMONY) {
|
| - return Bailout(kNonInitializerAssignmentToConst);
|
| + return Bailout("non-initializer assignment to const");
|
| }
|
| }
|
|
|
| - if (proxy->IsArguments()) return Bailout(kAssignmentToArguments);
|
| + if (proxy->IsArguments()) return Bailout("assignment to arguments");
|
|
|
| // Handle the assignment.
|
| switch (var->location()) {
|
| @@ -5139,7 +5218,7 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
|
| if (var->mode() == LET && expr->op() == Token::ASSIGN) {
|
| HValue* env_value = environment()->Lookup(var);
|
| if (env_value == graph()->GetConstantHole()) {
|
| - return Bailout(kAssignmentToLetVariableBeforeInitialization);
|
| + return Bailout("assignment to let variable before initialization");
|
| }
|
| }
|
| // We do not allow the arguments object to occur in a context where it
|
| @@ -5161,7 +5240,7 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
|
| int count = current_info()->scope()->num_parameters();
|
| for (int i = 0; i < count; ++i) {
|
| if (var == current_info()->scope()->parameter(i)) {
|
| - return Bailout(kAssignmentToParameterInArgumentsObject);
|
| + return Bailout("assignment to parameter in arguments object");
|
| }
|
| }
|
| }
|
| @@ -5202,10 +5281,10 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
|
| }
|
|
|
| case Variable::LOOKUP:
|
| - return Bailout(kAssignmentToLOOKUPVariable);
|
| + return Bailout("assignment to LOOKUP variable");
|
| }
|
| } else {
|
| - return Bailout(kInvalidLeftHandSideInAssignment);
|
| + return Bailout("invalid left-hand side in assignment");
|
| }
|
| }
|
|
|
| @@ -5327,7 +5406,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
|
| Handle<JSObject> holder(lookup.holder());
|
| Handle<Map> holder_map(holder->map());
|
| AddCheckMap(object, map);
|
| - BuildCheckPrototypeMaps(prototype, holder);
|
| + Add<HCheckPrototypeMaps>(prototype, holder, top_info());
|
| HValue* holder_value = Add<HConstant>(holder);
|
| return BuildLoadNamedField(holder_value,
|
| HObjectAccess::ForField(holder_map, &lookup, name));
|
| @@ -5339,7 +5418,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
|
| Handle<JSObject> holder(lookup.holder());
|
| Handle<Map> holder_map(holder->map());
|
| AddCheckMap(object, map);
|
| - BuildCheckPrototypeMaps(prototype, holder);
|
| + Add<HCheckPrototypeMaps>(prototype, holder, top_info());
|
| Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate());
|
| return New<HConstant>(constant);
|
| }
|
| @@ -5375,7 +5454,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
|
| isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
|
| Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
|
| Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
|
| - BuildCheckPrototypeMaps(prototype, object_prototype);
|
| + Add<HCheckPrototypeMaps>(prototype, object_prototype, top_info());
|
| load_mode = ALLOW_RETURN_HOLE;
|
| graph()->MarkDependsOnEmptyArrayProtoElements();
|
| }
|
| @@ -5821,38 +5900,11 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
|
| }
|
|
|
|
|
| -void HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
|
| - CompilationInfo* info) {
|
| - HConstant* constant_value = New<HConstant>(constant);
|
| -
|
| - if (constant->map()->CanOmitMapChecks()) {
|
| - constant->map()->AddDependentCompilationInfo(
|
| - DependentCode::kPrototypeCheckGroup, info);
|
| - return;
|
| - }
|
| -
|
| - AddInstruction(constant_value);
|
| - HCheckMaps* check =
|
| - Add<HCheckMaps>(constant_value, handle(constant->map()), info);
|
| - check->ClearGVNFlag(kDependsOnElementsKind);
|
| -}
|
| -
|
| -
|
| -void HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
|
| - Handle<JSObject> holder) {
|
| - BuildConstantMapCheck(prototype, top_info());
|
| - while (!prototype.is_identical_to(holder)) {
|
| - prototype = handle(JSObject::cast(prototype->GetPrototype()));
|
| - BuildConstantMapCheck(prototype, top_info());
|
| - }
|
| -}
|
| -
|
| -
|
| void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
|
| Handle<Map> receiver_map) {
|
| if (!holder.is_null()) {
|
| Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
|
| - BuildCheckPrototypeMaps(prototype, holder);
|
| + Add<HCheckPrototypeMaps>(prototype, holder, top_info());
|
| }
|
| }
|
|
|
| @@ -6224,7 +6276,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
| if (target_info.isolate()->has_pending_exception()) {
|
| // Parse or scope error, never optimize this function.
|
| SetStackOverflow();
|
| - target_shared->DisableOptimization(kParseScopeError);
|
| + target_shared->DisableOptimization("parse/scope error");
|
| }
|
| TraceInline(target, caller, "parse failure");
|
| return false;
|
| @@ -6363,7 +6415,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
| // Bail out if the inline function did, as we cannot residualize a call
|
| // instead.
|
| TraceInline(target, caller, "inline graph construction failed");
|
| - target_shared->DisableOptimization(kInliningBailedOut);
|
| + target_shared->DisableOptimization("inlining bailed out");
|
| inline_bailout_ = true;
|
| delete target_state;
|
| return true;
|
| @@ -6593,9 +6645,9 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| HValue* string = Pop();
|
| HValue* context = environment()->context();
|
| ASSERT(!expr->holder().is_null());
|
| - BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck(
|
| + Add<HCheckPrototypeMaps>(Call::GetPrototypeForPrimitiveCheck(
|
| STRING_CHECK, expr->holder()->GetIsolate()),
|
| - expr->holder());
|
| + expr->holder(), top_info());
|
| HInstruction* char_code =
|
| BuildStringCharCodeAt(string, index);
|
| if (id == kStringCharCodeAt) {
|
| @@ -6908,7 +6960,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
| } else {
|
| VariableProxy* proxy = expr->expression()->AsVariableProxy();
|
| if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
|
| - return Bailout(kPossibleDirectCallToEval);
|
| + return Bailout("possible direct call to eval");
|
| }
|
|
|
| bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
|
| @@ -7176,7 +7228,7 @@ void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| if (expr->is_jsruntime()) {
|
| - return Bailout(kCallToAJavaScriptRuntimeFunction);
|
| + return Bailout("call to a JavaScript runtime function");
|
| }
|
|
|
| const Runtime::Function* function = expr->function();
|
| @@ -7216,6 +7268,8 @@ void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
|
| case Token::DELETE: return VisitDelete(expr);
|
| case Token::VOID: return VisitVoid(expr);
|
| case Token::TYPEOF: return VisitTypeof(expr);
|
| + case Token::SUB: return VisitSub(expr);
|
| + case Token::BIT_NOT: return VisitBitNot(expr);
|
| case Token::NOT: return VisitNot(expr);
|
| default: UNREACHABLE();
|
| }
|
| @@ -7241,7 +7295,7 @@ void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
|
| } else if (proxy != NULL) {
|
| Variable* var = proxy->var();
|
| if (var->IsUnallocated()) {
|
| - Bailout(kDeleteWithGlobalVariable);
|
| + Bailout("delete with global variable");
|
| } else if (var->IsStackAllocated() || var->IsContextSlot()) {
|
| // Result of deleting non-global variables is false. 'this' is not
|
| // really a variable, though we implement it as one. The
|
| @@ -7251,7 +7305,7 @@ void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
|
| : graph()->GetConstantFalse();
|
| return ast_context()->ReturnValue(value);
|
| } else {
|
| - Bailout(kDeleteWithNonGlobalVariable);
|
| + Bailout("delete with non-global variable");
|
| }
|
| } else {
|
| // Result of deleting non-property, non-variable reference is true.
|
| @@ -7277,6 +7331,24 @@ void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
|
| }
|
|
|
|
|
| +void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) {
|
| + CHECK_ALIVE(VisitForValue(expr->expression()));
|
| + Handle<Type> operand_type = expr->expression()->bounds().lower;
|
| + HValue* value = TruncateToNumber(Pop(), &operand_type);
|
| + HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::SUB);
|
| + return ast_context()->ReturnInstruction(instr, expr->id());
|
| +}
|
| +
|
| +
|
| +void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) {
|
| + CHECK_ALIVE(VisitForValue(expr->expression()));
|
| + Handle<Type> operand_type = expr->expression()->bounds().lower;
|
| + HValue* value = TruncateToNumber(Pop(), &operand_type);
|
| + HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT);
|
| + return ast_context()->ReturnInstruction(instr, expr->id());
|
| +}
|
| +
|
| +
|
| void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
|
| if (ast_context()->IsTest()) {
|
| TestContext* context = TestContext::cast(ast_context());
|
| @@ -7365,7 +7437,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
| VariableProxy* proxy = target->AsVariableProxy();
|
| Property* prop = target->AsProperty();
|
| if (proxy == NULL && prop == NULL) {
|
| - return Bailout(kInvalidLhsInCountOperation);
|
| + return Bailout("invalid lhs in count operation");
|
| }
|
|
|
| // Match the full code generator stack by simulating an extra stack
|
| @@ -7379,7 +7451,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
| if (proxy != NULL) {
|
| Variable* var = proxy->var();
|
| if (var->mode() == CONST) {
|
| - return Bailout(kUnsupportedCountOperationWithConst);
|
| + return Bailout("unsupported count operation with const");
|
| }
|
| // Argument of the count operation is a variable, not a property.
|
| ASSERT(prop == NULL);
|
| @@ -7413,7 +7485,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
| int count = current_info()->scope()->num_parameters();
|
| for (int i = 0; i < count; ++i) {
|
| if (var == current_info()->scope()->parameter(i)) {
|
| - return Bailout(kAssignmentToParameterInArgumentsObject);
|
| + return Bailout("assignment to parameter in arguments object");
|
| }
|
| }
|
| }
|
| @@ -7430,7 +7502,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
| }
|
|
|
| case Variable::LOOKUP:
|
| - return Bailout(kLookupVariableInCountOperation);
|
| + return Bailout("lookup variable in count operation");
|
| }
|
|
|
| } else {
|
| @@ -8019,7 +8091,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
| }
|
| }
|
| default:
|
| - return Bailout(kUnsupportedNonPrimitiveCompare);
|
| + return Bailout("Unsupported non-primitive compare");
|
| }
|
| } else if (combined_type->Is(Type::InternalizedString()) &&
|
| Token::IsEqualityOp(op)) {
|
| @@ -8486,7 +8558,7 @@ void HOptimizedGraphBuilder::VisitVariableDeclaration(
|
| }
|
| break;
|
| case Variable::LOOKUP:
|
| - return Bailout(kUnsupportedLookupSlotInDeclaration);
|
| + return Bailout("unsupported lookup slot in declaration");
|
| }
|
| }
|
|
|
| @@ -8524,7 +8596,7 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration(
|
| break;
|
| }
|
| case Variable::LOOKUP:
|
| - return Bailout(kUnsupportedLookupSlotInDeclaration);
|
| + return Bailout("unsupported lookup slot in declaration");
|
| }
|
| }
|
|
|
| @@ -8645,7 +8717,7 @@ void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
|
|
|
|
|
| void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
|
| - return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
|
| + return Bailout("inlined runtime function: IsNonNegativeSmi");
|
| }
|
|
|
|
|
| @@ -8661,7 +8733,8 @@ void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
|
|
|
| void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
|
| CallRuntime* call) {
|
| - return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf);
|
| + return Bailout(
|
| + "inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
|
| }
|
|
|
|
|
| @@ -8715,7 +8788,7 @@ void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
|
| void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) {
|
| // The special form detected by IsClassOfTest is detected before we get here
|
| // and does not cause a bailout.
|
| - return Bailout(kInlinedRuntimeFunctionClassOf);
|
| + return Bailout("inlined runtime function: ClassOf");
|
| }
|
|
|
|
|
| @@ -8932,7 +9005,7 @@ void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
|
|
|
| // Support for fast native caches.
|
| void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
|
| - return Bailout(kInlinedRuntimeFunctionGetFromCache);
|
| + return Bailout("inlined runtime function: GetFromCache");
|
| }
|
|
|
|
|
| @@ -9062,7 +9135,7 @@ void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
|
|
|
| // Check whether two RegExps are equivalent
|
| void HOptimizedGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) {
|
| - return Bailout(kInlinedRuntimeFunctionIsRegExpEquivalent);
|
| + return Bailout("inlined runtime function: IsRegExpEquivalent");
|
| }
|
|
|
|
|
| @@ -9076,18 +9149,18 @@ void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
|
|
|
|
|
| void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
|
| - return Bailout(kInlinedRuntimeFunctionFastAsciiArrayJoin);
|
| + return Bailout("inlined runtime function: FastAsciiArrayJoin");
|
| }
|
|
|
|
|
| // Support for generators.
|
| void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) {
|
| - return Bailout(kInlinedRuntimeFunctionGeneratorNext);
|
| + return Bailout("inlined runtime function: GeneratorNext");
|
| }
|
|
|
|
|
| void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) {
|
| - return Bailout(kInlinedRuntimeFunctionGeneratorThrow);
|
| + return Bailout("inlined runtime function: GeneratorThrow");
|
| }
|
|
|
|
|
|
|