Commit e25e6ab2 authored by verwaest@chromium.org's avatar verwaest@chromium.org

Let BuildStore/BuildLoad distinguish between keyed/named load/stores.

R=bmeurer@chromium.org

Review URL: https://chromiumcodereview.appspot.com/23537024

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16575 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b2564755
...@@ -4896,109 +4896,51 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( ...@@ -4896,109 +4896,51 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
} }
void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { static bool ComputeReceiverTypes(Expression* expr,
Property* prop = expr->target()->AsProperty(); HValue* receiver,
ASSERT(prop != NULL); SmallMapList** t) {
CHECK_ALIVE(VisitForValue(prop->obj())); 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. void HOptimizedGraphBuilder::BuildStore(Expression* expr,
CHECK_ALIVE(VisitForValue(expr->value())); Property* prop,
BailoutId ast_id,
BailoutId return_id,
bool is_uninitialized) {
HValue* value = environment()->ExpressionStackAt(0); HValue* value = environment()->ExpressionStackAt(0);
HValue* object = environment()->ExpressionStackAt(1);
if (expr->IsUninitialized()) { if (!prop->key()->IsPropertyName()) {
Add<HDeoptimize>("Insufficient type feedback for property assignment",
Deoptimizer::SOFT);
}
return BuildStoreNamed(
expr, expr->id(), expr->AssignmentId(), prop, object, value);
} else {
// Keyed store. // Keyed store.
CHECK_ALIVE(VisitForValue(prop->key()));
CHECK_ALIVE(VisitForValue(expr->value()));
HValue* value = environment()->ExpressionStackAt(0);
HValue* key = environment()->ExpressionStackAt(1); HValue* key = environment()->ExpressionStackAt(1);
HValue* object = environment()->ExpressionStackAt(2); HValue* object = environment()->ExpressionStackAt(2);
bool has_side_effects = false; bool has_side_effects = false;
HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(), HandleKeyedElementAccess(object, key, value, expr, return_id,
expr->position(), expr->position(),
true, // is_store true, // is_store
&has_side_effects); &has_side_effects);
Drop(3); Drop(3);
Push(value); Push(value);
Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); Add<HSimulate>(return_id, REMOVABLE_SIMULATE);
return ast_context()->ReturnValue(Pop()); 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, if (is_uninitialized) {
HValue* receiver, Add<HDeoptimize>("Insufficient type feedback for property assignment",
SmallMapList** t) { Deoptimizer::SOFT);
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());
}
void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
BailoutId id,
BailoutId assignment_id,
Property* prop,
HValue* object,
HValue* value) {
Literal* key = prop->key()->AsLiteral(); Literal* key = prop->key()->AsLiteral();
Handle<String> name = Handle<String>::cast(key->value()); Handle<String> name = Handle<String>::cast(key->value());
ASSERT(!name.is_null()); ASSERT(!name.is_null());
...@@ -5015,7 +4957,7 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, ...@@ -5015,7 +4957,7 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
if (LookupSetter(map, name, &setter, &holder)) { if (LookupSetter(map, name, &setter, &holder)) {
AddCheckConstantFunction(holder, object, map); AddCheckConstantFunction(holder, object, map);
if (FLAG_inline_accessors && if (FLAG_inline_accessors &&
TryInlineSetter(setter, id, assignment_id, value)) { TryInlineSetter(setter, ast_id, return_id, value)) {
return; return;
} }
Drop(2); Drop(2);
...@@ -5032,7 +4974,7 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, ...@@ -5032,7 +4974,7 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
} else if (types != NULL && types->length() > 1) { } else if (types != NULL && types->length() > 1) {
Drop(2); Drop(2);
return HandlePolymorphicStoreNamedField( return HandlePolymorphicStoreNamedField(
expr->position(), id, object, value, types, name); expr->position(), ast_id, object, value, types, name);
} else { } else {
Drop(2); Drop(2);
instr = BuildStoreNamedGeneric(object, name, value); instr = BuildStoreNamedGeneric(object, name, value);
...@@ -5042,13 +4984,71 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, ...@@ -5042,13 +4984,71 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr,
instr->set_position(expr->position()); instr->set_position(expr->position());
AddInstruction(instr); AddInstruction(instr);
if (instr->HasObservableSideEffects()) { if (instr->HasObservableSideEffects()) {
Add<HSimulate>(id, REMOVABLE_SIMULATE); Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
} }
if (!ast_context()->IsEffect()) Drop(1); if (!ast_context()->IsEffect()) Drop(1);
return ast_context()->ReturnValue(value); 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) { void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
Expression* target = expr->target(); Expression* target = expr->target();
VariableProxy* proxy = target->AsVariableProxy(); VariableProxy* proxy = target->AsVariableProxy();
...@@ -5130,38 +5130,18 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ...@@ -5130,38 +5130,18 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
return ast_context()->ReturnValue(Pop()); return ast_context()->ReturnValue(Pop());
} else if (prop != NULL) { } else if (prop != NULL) {
if (prop->key()->IsPropertyName()) {
// Named property.
CHECK_ALIVE(VisitForValue(prop->obj())); CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* object = Top(); HValue* object = Top();
CHECK_ALIVE(PushLoad(prop, object, expr->position())); HValue* key = NULL;
if ((!prop->IsStringLength() &&
CHECK_ALIVE(VisitForValue(expr->value())); !prop->IsFunctionPrototype() &&
HValue* right = Pop(); !prop->key()->IsPropertyName()) ||
HValue* left = Pop(); prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
HInstruction* instr = BuildBinaryOperation(operation, left, right); key = Top();
PushAndAdd(instr);
if (instr->HasObservableSideEffects()) {
Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
} }
return BuildStoreNamed( CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
expr, expr->id(), expr->AssignmentId(), prop, object, instr);
} else {
// Keyed property.
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);
CHECK_ALIVE(VisitForValue(expr->value())); CHECK_ALIVE(VisitForValue(expr->value()));
HValue* right = Pop(); HValue* right = Pop();
...@@ -5172,20 +5152,8 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ...@@ -5172,20 +5152,8 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
if (instr->HasObservableSideEffects()) { if (instr->HasObservableSideEffects()) {
Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
} }
BuildStore(expr, prop, expr->id(),
HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), expr->AssignmentId(), expr->IsUninitialized());
RelocInfo::kNoPosition,
true, // is_store
&has_side_effects);
// 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());
}
} else { } else {
return Bailout(kInvalidLhsInCompoundAssignment); return Bailout(kInvalidLhsInCompoundAssignment);
} }
...@@ -5840,9 +5808,11 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { ...@@ -5840,9 +5808,11 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
void HOptimizedGraphBuilder::PushLoad(Property* expr, void HOptimizedGraphBuilder::PushLoad(Property* expr,
HValue* object, HValue* object,
HValue* key,
int position) { int position) {
ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
Push(object); Push(object);
if (key != NULL) Push(key);
BuildLoad(expr, position, expr->LoadId()); BuildLoad(expr, position, expr->LoadId());
} }
...@@ -5858,7 +5828,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, ...@@ -5858,7 +5828,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
AddInstruction(HCheckInstanceType::NewIsString(string, zone())); AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
instr = BuildLoadStringLength(string, checkstring); instr = BuildLoadStringLength(string, checkstring);
} else if (expr->IsStringAccess()) { } else if (expr->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(expr->key()));
HValue* index = Pop(); HValue* index = Pop();
HValue* string = Pop(); HValue* string = Pop();
HValue* context = environment()->context(); HValue* context = environment()->context();
...@@ -5902,8 +5871,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, ...@@ -5902,8 +5871,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
} }
} else { } else {
CHECK_ALIVE(VisitForValue(expr->key()));
HValue* key = Pop(); HValue* key = Pop();
HValue* obj = Pop(); HValue* obj = Pop();
...@@ -5936,6 +5903,13 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { ...@@ -5936,6 +5903,13 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
if (TryArgumentsAccess(expr)) return; if (TryArgumentsAccess(expr)) return;
CHECK_ALIVE(VisitForValue(expr->obj())); 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()); BuildLoad(expr, expr->position(), expr->id());
} }
...@@ -7478,16 +7452,18 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement( ...@@ -7478,16 +7452,18 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(
} }
void HOptimizedGraphBuilder::BuildStoreInEffect(Expression* expr, void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr,
Property* prop, Property* prop,
BailoutId ast_id, BailoutId ast_id,
BailoutId return_id, BailoutId return_id,
HValue* object, HValue* object,
HValue* key,
HValue* value) { HValue* value) {
EffectContext for_effect(this); EffectContext for_effect(this);
Push(object); Push(object);
if (key != NULL) Push(key);
Push(value); 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) { ...@@ -7567,69 +7543,42 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
return Bailout(kLookupVariableInCountOperation); return Bailout(kLookupVariableInCountOperation);
} }
} else { Drop(returns_original_input ? 2 : 1);
return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
}
// Argument of the count operation is a property. // Argument of the count operation is a property.
ASSERT(prop != NULL); ASSERT(prop != NULL);
if (prop->key()->IsPropertyName()) {
// Named property.
if (returns_original_input) Push(graph()->GetConstantUndefined()); if (returns_original_input) Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitForValue(prop->obj())); CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* object = Top(); HValue* object = Top();
CHECK_ALIVE(PushLoad(prop, object, expr->position()));
after = BuildIncrement(returns_original_input, expr); HValue* key = NULL;
if ((!prop->IsStringLength() &&
if (returns_original_input) { !prop->IsFunctionPrototype() &&
HValue* result = Pop(); !prop->key()->IsPropertyName()) ||
HValue* object = Pop(); prop->IsStringAccess()) {
environment()->SetExpressionStackAt(0, result);
CHECK_ALIVE(BuildStoreInEffect(
expr, prop, expr->id(), expr->AssignmentId(), object, after));
return ast_context()->ReturnValue(Pop());
}
return BuildStoreNamed(
expr, expr->id(), expr->AssignmentId(), prop, object, after);
} else {
// Keyed property.
if (returns_original_input) Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitForValue(prop->obj()));
CHECK_ALIVE(VisitForValue(prop->key())); CHECK_ALIVE(VisitForValue(prop->key()));
HValue* obj = environment()->ExpressionStackAt(1); key = Top();
HValue* key = environment()->ExpressionStackAt(0); }
bool has_side_effects = false; CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
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); after = BuildIncrement(returns_original_input, expr);
input = environment()->ExpressionStackAt(0);
HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(), if (returns_original_input) {
RelocInfo::kNoPosition, input = Pop();
true, // is_store // Drop object and key to push it again in the effect context below.
&has_side_effects); Drop(key == NULL ? 1 : 2);
environment()->SetExpressionStackAt(0, input);
// Drop the key and the original value from the bailout environment. CHECK_ALIVE(BuildStoreForEffect(
// Overwrite the receiver with the result of the operation, and the expr, prop, expr->id(), expr->AssignmentId(), object, key, after));
// placeholder with the original value if necessary. return ast_context()->ReturnValue(Pop());
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);
}
} }
Drop(returns_original_input ? 2 : 1); environment()->SetExpressionStackAt(0, after);
return ast_context()->ReturnValue(expr->is_postfix() ? input : after); return BuildStore(expr, prop, expr->id(), expr->AssignmentId());
} }
......
...@@ -2038,21 +2038,22 @@ class HOptimizedGraphBuilder V8_FINAL ...@@ -2038,21 +2038,22 @@ class HOptimizedGraphBuilder V8_FINAL
BailoutId ast_id); BailoutId ast_id);
void PushLoad(Property* property, void PushLoad(Property* property,
HValue* object, HValue* object,
HValue* key,
int position); int position);
void BuildStoreInEffect(Expression* expression, void BuildStoreForEffect(Expression* expression,
Property* prop, Property* prop,
BailoutId ast_id, BailoutId ast_id,
BailoutId return_id, BailoutId return_id,
HValue* object, HValue* object,
HValue* key,
HValue* value); HValue* value);
void BuildStoreNamed(Expression* expression, void BuildStore(Expression* expression,
BailoutId id,
BailoutId assignment_id,
Property* prop, Property* prop,
HValue* object, BailoutId ast_id,
HValue* value); BailoutId return_id,
bool is_uninitialized = false);
HInstruction* BuildStoreNamedField(HValue* object, HInstruction* BuildStoreNamedField(HValue* object,
Handle<String> name, Handle<String> name,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment