| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index bd9b0d69967ecec4e3e3b2a99afee473d81b30ce..3cbe1cb392751a97f5568d110a9c2140cbe7f73a 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -4896,109 +4896,51 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
|
| }
|
|
|
|
|
| -void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
|
| - Property* prop = expr->target()->AsProperty();
|
| - ASSERT(prop != NULL);
|
| - CHECK_ALIVE(VisitForValue(prop->obj()));
|
| +static bool ComputeReceiverTypes(Expression* expr,
|
| + HValue* receiver,
|
| + SmallMapList** t) {
|
| + SmallMapList* types = expr->GetReceiverTypes();
|
| + *t = types;
|
| + bool monomorphic = expr->IsMonomorphic();
|
| + if (types != NULL && receiver->HasMonomorphicJSObjectType()) {
|
| + Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
|
| + types->FilterForPossibleTransitions(root_map);
|
| + monomorphic = types->length() == 1;
|
| + }
|
| + return monomorphic && CanInlinePropertyAccess(*types->first());
|
| +}
|
|
|
| - if (prop->key()->IsPropertyName()) {
|
| - // Named store.
|
| - CHECK_ALIVE(VisitForValue(expr->value()));
|
| - HValue* value = environment()->ExpressionStackAt(0);
|
| - HValue* object = environment()->ExpressionStackAt(1);
|
|
|
| - if (expr->IsUninitialized()) {
|
| - Add<HDeoptimize>("Insufficient type feedback for property assignment",
|
| - Deoptimizer::SOFT);
|
| - }
|
| - return BuildStoreNamed(
|
| - expr, expr->id(), expr->AssignmentId(), prop, object, value);
|
| - } else {
|
| +void HOptimizedGraphBuilder::BuildStore(Expression* expr,
|
| + Property* prop,
|
| + BailoutId ast_id,
|
| + BailoutId return_id,
|
| + bool is_uninitialized) {
|
| + HValue* value = environment()->ExpressionStackAt(0);
|
| +
|
| + if (!prop->key()->IsPropertyName()) {
|
| // Keyed store.
|
| - CHECK_ALIVE(VisitForValue(prop->key()));
|
| - CHECK_ALIVE(VisitForValue(expr->value()));
|
| - HValue* value = environment()->ExpressionStackAt(0);
|
| HValue* key = environment()->ExpressionStackAt(1);
|
| HValue* object = environment()->ExpressionStackAt(2);
|
| bool has_side_effects = false;
|
| - HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
|
| + HandleKeyedElementAccess(object, key, value, expr, return_id,
|
| expr->position(),
|
| true, // is_store
|
| &has_side_effects);
|
| Drop(3);
|
| Push(value);
|
| - Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
|
| + Add<HSimulate>(return_id, REMOVABLE_SIMULATE);
|
| return ast_context()->ReturnValue(Pop());
|
| }
|
| -}
|
| -
|
| -
|
| -// Because not every expression has a position and there is not common
|
| -// superclass of Assignment and CountOperation, we cannot just pass the
|
| -// owning expression instead of position and ast_id separately.
|
| -void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
|
| - Variable* var,
|
| - HValue* value,
|
| - int position,
|
| - BailoutId ast_id) {
|
| - LookupResult lookup(isolate());
|
| - GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
|
| - if (type == kUseCell) {
|
| - Handle<GlobalObject> global(current_info()->global_object());
|
| - Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
|
| - if (cell->type()->IsConstant()) {
|
| - IfBuilder builder(this);
|
| - HValue* constant = Add<HConstant>(cell->type()->AsConstant());
|
| - if (cell->type()->AsConstant()->IsNumber()) {
|
| - builder.If<HCompareNumericAndBranch>(value, constant, Token::EQ);
|
| - } else {
|
| - builder.If<HCompareObjectEqAndBranch>(value, constant);
|
| - }
|
| - builder.Then();
|
| - builder.Else();
|
| - Add<HDeoptimize>("Constant global variable assignment",
|
| - Deoptimizer::EAGER);
|
| - builder.End();
|
| - }
|
| - HInstruction* instr =
|
| - Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
|
| - instr->set_position(position);
|
| - if (instr->HasObservableSideEffects()) {
|
| - Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
|
| - }
|
| - } else {
|
| - HGlobalObject* global_object = Add<HGlobalObject>();
|
| - HStoreGlobalGeneric* instr =
|
| - Add<HStoreGlobalGeneric>(global_object, var->name(),
|
| - value, function_strict_mode_flag());
|
| - instr->set_position(position);
|
| - ASSERT(instr->HasObservableSideEffects());
|
| - Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
|
| - }
|
| -}
|
|
|
| + // Named store.
|
| + HValue* object = environment()->ExpressionStackAt(1);
|
|
|
| -static bool ComputeReceiverTypes(Expression* expr,
|
| - HValue* receiver,
|
| - SmallMapList** t) {
|
| - SmallMapList* types = expr->GetReceiverTypes();
|
| - *t = types;
|
| - bool monomorphic = expr->IsMonomorphic();
|
| - if (types != NULL && receiver->HasMonomorphicJSObjectType()) {
|
| - Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
|
| - types->FilterForPossibleTransitions(root_map);
|
| - monomorphic = types->length() == 1;
|
| + if (is_uninitialized) {
|
| + Add<HDeoptimize>("Insufficient type feedback for property assignment",
|
| + Deoptimizer::SOFT);
|
| }
|
| - return monomorphic && CanInlinePropertyAccess(*types->first());
|
| -}
|
| -
|
|
|
| -void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
|
| - BailoutId id,
|
| - BailoutId assignment_id,
|
| - Property* prop,
|
| - HValue* object,
|
| - HValue* value) {
|
| Literal* key = prop->key()->AsLiteral();
|
| Handle<String> name = Handle<String>::cast(key->value());
|
| ASSERT(!name.is_null());
|
| @@ -5015,7 +4957,7 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
|
| if (LookupSetter(map, name, &setter, &holder)) {
|
| AddCheckConstantFunction(holder, object, map);
|
| if (FLAG_inline_accessors &&
|
| - TryInlineSetter(setter, id, assignment_id, value)) {
|
| + TryInlineSetter(setter, ast_id, return_id, value)) {
|
| return;
|
| }
|
| Drop(2);
|
| @@ -5032,7 +4974,7 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
|
| } else if (types != NULL && types->length() > 1) {
|
| Drop(2);
|
| return HandlePolymorphicStoreNamedField(
|
| - expr->position(), id, object, value, types, name);
|
| + expr->position(), ast_id, object, value, types, name);
|
| } else {
|
| Drop(2);
|
| instr = BuildStoreNamedGeneric(object, name, value);
|
| @@ -5042,13 +4984,71 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
|
| instr->set_position(expr->position());
|
| AddInstruction(instr);
|
| if (instr->HasObservableSideEffects()) {
|
| - Add<HSimulate>(id, REMOVABLE_SIMULATE);
|
| + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
|
| }
|
| if (!ast_context()->IsEffect()) Drop(1);
|
| return ast_context()->ReturnValue(value);
|
| }
|
|
|
|
|
| +void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
|
| + Property* prop = expr->target()->AsProperty();
|
| + ASSERT(prop != NULL);
|
| + CHECK_ALIVE(VisitForValue(prop->obj()));
|
| + if (!prop->key()->IsPropertyName()) {
|
| + CHECK_ALIVE(VisitForValue(prop->key()));
|
| + }
|
| + CHECK_ALIVE(VisitForValue(expr->value()));
|
| + BuildStore(expr, prop, expr->id(),
|
| + expr->AssignmentId(), expr->IsUninitialized());
|
| +}
|
| +
|
| +
|
| +// Because not every expression has a position and there is not common
|
| +// superclass of Assignment and CountOperation, we cannot just pass the
|
| +// owning expression instead of position and ast_id separately.
|
| +void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
|
| + Variable* var,
|
| + HValue* value,
|
| + int position,
|
| + BailoutId ast_id) {
|
| + LookupResult lookup(isolate());
|
| + GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
|
| + if (type == kUseCell) {
|
| + Handle<GlobalObject> global(current_info()->global_object());
|
| + Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
|
| + if (cell->type()->IsConstant()) {
|
| + IfBuilder builder(this);
|
| + HValue* constant = Add<HConstant>(cell->type()->AsConstant());
|
| + if (cell->type()->AsConstant()->IsNumber()) {
|
| + builder.If<HCompareNumericAndBranch>(value, constant, Token::EQ);
|
| + } else {
|
| + builder.If<HCompareObjectEqAndBranch>(value, constant);
|
| + }
|
| + builder.Then();
|
| + builder.Else();
|
| + Add<HDeoptimize>("Constant global variable assignment",
|
| + Deoptimizer::EAGER);
|
| + builder.End();
|
| + }
|
| + HInstruction* instr =
|
| + Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
|
| + instr->set_position(position);
|
| + if (instr->HasObservableSideEffects()) {
|
| + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
|
| + }
|
| + } else {
|
| + HGlobalObject* global_object = Add<HGlobalObject>();
|
| + HStoreGlobalGeneric* instr =
|
| + Add<HStoreGlobalGeneric>(global_object, var->name(),
|
| + value, function_strict_mode_flag());
|
| + instr->set_position(position);
|
| + ASSERT(instr->HasObservableSideEffects());
|
| + Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
|
| + }
|
| +}
|
| +
|
| +
|
| void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| Expression* target = expr->target();
|
| VariableProxy* proxy = target->AsVariableProxy();
|
| @@ -5130,62 +5130,30 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| return ast_context()->ReturnValue(Pop());
|
|
|
| } else if (prop != NULL) {
|
| - if (prop->key()->IsPropertyName()) {
|
| - // Named property.
|
| - CHECK_ALIVE(VisitForValue(prop->obj()));
|
| - HValue* object = Top();
|
| - CHECK_ALIVE(PushLoad(prop, object, expr->position()));
|
| -
|
| - CHECK_ALIVE(VisitForValue(expr->value()));
|
| - HValue* right = Pop();
|
| - HValue* left = Pop();
|
| -
|
| - HInstruction* instr = BuildBinaryOperation(operation, left, right);
|
| - PushAndAdd(instr);
|
| - if (instr->HasObservableSideEffects()) {
|
| - Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
|
| - }
|
| -
|
| - return BuildStoreNamed(
|
| - expr, expr->id(), expr->AssignmentId(), prop, object, instr);
|
| - } else {
|
| - // Keyed property.
|
| - CHECK_ALIVE(VisitForValue(prop->obj()));
|
| + CHECK_ALIVE(VisitForValue(prop->obj()));
|
| + HValue* object = Top();
|
| + HValue* key = NULL;
|
| + if ((!prop->IsStringLength() &&
|
| + !prop->IsFunctionPrototype() &&
|
| + !prop->key()->IsPropertyName()) ||
|
| + prop->IsStringAccess()) {
|
| CHECK_ALIVE(VisitForValue(prop->key()));
|
| - HValue* obj = environment()->ExpressionStackAt(1);
|
| - HValue* key = environment()->ExpressionStackAt(0);
|
| -
|
| - bool has_side_effects = false;
|
| - HValue* load = HandleKeyedElementAccess(
|
| - obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition,
|
| - false, // is_store
|
| - &has_side_effects);
|
| - Push(load);
|
| - if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE);
|
| -
|
| - CHECK_ALIVE(VisitForValue(expr->value()));
|
| - HValue* right = Pop();
|
| - HValue* left = Pop();
|
| -
|
| - HInstruction* instr = BuildBinaryOperation(operation, left, right);
|
| - PushAndAdd(instr);
|
| - if (instr->HasObservableSideEffects()) {
|
| - Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
|
| - }
|
| + key = Top();
|
| + }
|
|
|
| - HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
|
| - RelocInfo::kNoPosition,
|
| - true, // is_store
|
| - &has_side_effects);
|
| + CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
|
|
|
| - // Drop the simulated receiver, key, and value. Return the value.
|
| - Drop(3);
|
| - Push(instr);
|
| - ASSERT(has_side_effects); // Stores always have side effects.
|
| - Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
|
| - return ast_context()->ReturnValue(Pop());
|
| - }
|
| + CHECK_ALIVE(VisitForValue(expr->value()));
|
| + HValue* right = Pop();
|
| + HValue* left = Pop();
|
|
|
| + HInstruction* instr = BuildBinaryOperation(operation, left, right);
|
| + PushAndAdd(instr);
|
| + if (instr->HasObservableSideEffects()) {
|
| + Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
|
| + }
|
| + BuildStore(expr, prop, expr->id(),
|
| + expr->AssignmentId(), expr->IsUninitialized());
|
| } else {
|
| return Bailout(kInvalidLhsInCompoundAssignment);
|
| }
|
| @@ -5840,9 +5808,11 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
|
|
|
| void HOptimizedGraphBuilder::PushLoad(Property* expr,
|
| HValue* object,
|
| + HValue* key,
|
| int position) {
|
| ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
|
| Push(object);
|
| + if (key != NULL) Push(key);
|
| BuildLoad(expr, position, expr->LoadId());
|
| }
|
|
|
| @@ -5858,7 +5828,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
|
| AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
|
| instr = BuildLoadStringLength(string, checkstring);
|
| } else if (expr->IsStringAccess()) {
|
| - CHECK_ALIVE(VisitForValue(expr->key()));
|
| HValue* index = Pop();
|
| HValue* string = Pop();
|
| HValue* context = environment()->context();
|
| @@ -5902,8 +5871,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
|
| }
|
|
|
| } else {
|
| - CHECK_ALIVE(VisitForValue(expr->key()));
|
| -
|
| HValue* key = Pop();
|
| HValue* obj = Pop();
|
|
|
| @@ -5936,6 +5903,13 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
|
| if (TryArgumentsAccess(expr)) return;
|
|
|
| CHECK_ALIVE(VisitForValue(expr->obj()));
|
| + if ((!expr->IsStringLength() &&
|
| + !expr->IsFunctionPrototype() &&
|
| + !expr->key()->IsPropertyName()) ||
|
| + expr->IsStringAccess()) {
|
| + CHECK_ALIVE(VisitForValue(expr->key()));
|
| + }
|
| +
|
| BuildLoad(expr, expr->position(), expr->id());
|
| }
|
|
|
| @@ -7478,16 +7452,18 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(
|
| }
|
|
|
|
|
| -void HOptimizedGraphBuilder::BuildStoreInEffect(Expression* expr,
|
| - Property* prop,
|
| - BailoutId ast_id,
|
| - BailoutId return_id,
|
| - HValue* object,
|
| - HValue* value) {
|
| +void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr,
|
| + Property* prop,
|
| + BailoutId ast_id,
|
| + BailoutId return_id,
|
| + HValue* object,
|
| + HValue* key,
|
| + HValue* value) {
|
| EffectContext for_effect(this);
|
| Push(object);
|
| + if (key != NULL) Push(key);
|
| Push(value);
|
| - BuildStoreNamed(expr, ast_id, return_id, prop, object, value);
|
| + BuildStore(expr, prop, ast_id, return_id);
|
| }
|
|
|
|
|
| @@ -7567,69 +7543,42 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
| return Bailout(kLookupVariableInCountOperation);
|
| }
|
|
|
| - } else {
|
| - // Argument of the count operation is a property.
|
| - ASSERT(prop != NULL);
|
| + Drop(returns_original_input ? 2 : 1);
|
| + return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
|
| + }
|
|
|
| - if (prop->key()->IsPropertyName()) {
|
| - // Named property.
|
| - if (returns_original_input) Push(graph()->GetConstantUndefined());
|
| + // Argument of the count operation is a property.
|
| + ASSERT(prop != NULL);
|
| + if (returns_original_input) Push(graph()->GetConstantUndefined());
|
|
|
| - CHECK_ALIVE(VisitForValue(prop->obj()));
|
| - HValue* object = Top();
|
| - CHECK_ALIVE(PushLoad(prop, object, expr->position()));
|
| + CHECK_ALIVE(VisitForValue(prop->obj()));
|
| + HValue* object = Top();
|
|
|
| - after = BuildIncrement(returns_original_input, expr);
|
| + HValue* key = NULL;
|
| + if ((!prop->IsStringLength() &&
|
| + !prop->IsFunctionPrototype() &&
|
| + !prop->key()->IsPropertyName()) ||
|
| + prop->IsStringAccess()) {
|
| + CHECK_ALIVE(VisitForValue(prop->key()));
|
| + key = Top();
|
| + }
|
|
|
| - if (returns_original_input) {
|
| - HValue* result = Pop();
|
| - HValue* object = Pop();
|
| - environment()->SetExpressionStackAt(0, result);
|
| - CHECK_ALIVE(BuildStoreInEffect(
|
| - expr, prop, expr->id(), expr->AssignmentId(), object, after));
|
| - return ast_context()->ReturnValue(Pop());
|
| - }
|
| + CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
|
|
|
| - return BuildStoreNamed(
|
| - expr, expr->id(), expr->AssignmentId(), prop, object, after);
|
| - } else {
|
| - // Keyed property.
|
| - if (returns_original_input) Push(graph()->GetConstantUndefined());
|
| + after = BuildIncrement(returns_original_input, expr);
|
|
|
| - CHECK_ALIVE(VisitForValue(prop->obj()));
|
| - CHECK_ALIVE(VisitForValue(prop->key()));
|
| - HValue* obj = environment()->ExpressionStackAt(1);
|
| - HValue* key = environment()->ExpressionStackAt(0);
|
| -
|
| - bool has_side_effects = false;
|
| - HValue* load = HandleKeyedElementAccess(
|
| - obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition,
|
| - false, // is_store
|
| - &has_side_effects);
|
| - Push(load);
|
| - if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE);
|
| -
|
| - after = BuildIncrement(returns_original_input, expr);
|
| - input = environment()->ExpressionStackAt(0);
|
| -
|
| - HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
|
| - RelocInfo::kNoPosition,
|
| - true, // is_store
|
| - &has_side_effects);
|
| -
|
| - // Drop the key and the original value from the bailout environment.
|
| - // Overwrite the receiver with the result of the operation, and the
|
| - // placeholder with the original value if necessary.
|
| - Drop(2);
|
| - environment()->SetExpressionStackAt(0, after);
|
| - if (returns_original_input) environment()->SetExpressionStackAt(1, input);
|
| - ASSERT(has_side_effects); // Stores always have side effects.
|
| - Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
|
| - }
|
| + if (returns_original_input) {
|
| + input = Pop();
|
| + // Drop object and key to push it again in the effect context below.
|
| + Drop(key == NULL ? 1 : 2);
|
| + environment()->SetExpressionStackAt(0, input);
|
| + CHECK_ALIVE(BuildStoreForEffect(
|
| + expr, prop, expr->id(), expr->AssignmentId(), object, key, after));
|
| + return ast_context()->ReturnValue(Pop());
|
| }
|
|
|
| - Drop(returns_original_input ? 2 : 1);
|
| - return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
|
| + environment()->SetExpressionStackAt(0, after);
|
| + return BuildStore(expr, prop, expr->id(), expr->AssignmentId());
|
| }
|
|
|
|
|
|
|