Skip to content

Commit 36f3f90

Browse files
otherdanielCommit bot
authored andcommitted
Speedup access to global_proxy.* attributes/accessors.
Using a global proxy (e.g. 'window.f', 'w.f' or 'this.f') is considerably slower than evaluating just 'f'. This CL aims to perform the necessary checks at compile time and inline the accesses. This is a follow-on CL to crrev.com/2369933005: - The initial upload is crrev.com/2369933005 + a rebase. - The remaining issues are the fixes requested by the reviewers on that CL. BUG=chromium:634276, chromium:654716, chromium:656959 Committed: https://crrev.com/8f43d748272536117008aa6a1b53ea52126261c1 Committed: https://crrev.com/041314524952a3c1bc71bd3beafbbb37319f1d22 Review-Url: https://codereview.chromium.org/2403003002 Cr-Original-Original-Commit-Position: refs/heads/master@{#40153} Cr-Original-Commit-Position: refs/heads/master@{#40365} Cr-Commit-Position: refs/heads/master@{#40671}
1 parent 2654776 commit 36f3f90

2 files changed

Lines changed: 168 additions & 126 deletions

File tree

src/crankshaft/hydrogen.cc

Lines changed: 159 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -5199,12 +5199,16 @@ void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
51995199
}
52005200
}
52015201

5202+
bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
5203+
Variable* var, LookupIterator* it, PropertyAccessType access_type) {
5204+
if (var->is_this()) return false;
5205+
return CanInlineGlobalPropertyAccess(it, access_type);
5206+
}
52025207

5203-
HOptimizedGraphBuilder::GlobalPropertyAccess
5204-
HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
5205-
PropertyAccessType access_type) {
5206-
if (var->is_this() || !current_info()->has_global_object()) {
5207-
return kUseGeneric;
5208+
bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
5209+
LookupIterator* it, PropertyAccessType access_type) {
5210+
if (!current_info()->has_global_object()) {
5211+
return false;
52085212
}
52095213

52105214
switch (it->state()) {
@@ -5213,17 +5217,17 @@ HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
52135217
case LookupIterator::INTERCEPTOR:
52145218
case LookupIterator::INTEGER_INDEXED_EXOTIC:
52155219
case LookupIterator::NOT_FOUND:
5216-
return kUseGeneric;
5220+
return false;
52175221
case LookupIterator::DATA:
5218-
if (access_type == STORE && it->IsReadOnly()) return kUseGeneric;
5219-
if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return kUseGeneric;
5220-
return kUseCell;
5222+
if (access_type == STORE && it->IsReadOnly()) return false;
5223+
if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return false;
5224+
return true;
52215225
case LookupIterator::JSPROXY:
52225226
case LookupIterator::TRANSITION:
52235227
UNREACHABLE();
52245228
}
52255229
UNREACHABLE();
5226-
return kUseGeneric;
5230+
return false;
52275231
}
52285232

52295233

@@ -5239,6 +5243,55 @@ HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
52395243
return context;
52405244
}
52415245

5246+
void HOptimizedGraphBuilder::InlineGlobalPropertyLoad(LookupIterator* it,
5247+
BailoutId ast_id) {
5248+
Handle<PropertyCell> cell = it->GetPropertyCell();
5249+
top_info()->dependencies()->AssumePropertyCell(cell);
5250+
auto cell_type = it->property_details().cell_type();
5251+
if (cell_type == PropertyCellType::kConstant ||
5252+
cell_type == PropertyCellType::kUndefined) {
5253+
Handle<Object> constant_object(cell->value(), isolate());
5254+
if (constant_object->IsConsString()) {
5255+
constant_object = String::Flatten(Handle<String>::cast(constant_object));
5256+
}
5257+
HConstant* constant = New<HConstant>(constant_object);
5258+
return ast_context()->ReturnInstruction(constant, ast_id);
5259+
} else {
5260+
auto access = HObjectAccess::ForPropertyCellValue();
5261+
UniqueSet<Map>* field_maps = nullptr;
5262+
if (cell_type == PropertyCellType::kConstantType) {
5263+
switch (cell->GetConstantType()) {
5264+
case PropertyCellConstantType::kSmi:
5265+
access = access.WithRepresentation(Representation::Smi());
5266+
break;
5267+
case PropertyCellConstantType::kStableMap: {
5268+
// Check that the map really is stable. The heap object could
5269+
// have mutated without the cell updating state. In that case,
5270+
// make no promises about the loaded value except that it's a
5271+
// heap object.
5272+
access = access.WithRepresentation(Representation::HeapObject());
5273+
Handle<Map> map(HeapObject::cast(cell->value())->map());
5274+
if (map->is_stable()) {
5275+
field_maps = new (zone())
5276+
UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone());
5277+
}
5278+
break;
5279+
}
5280+
}
5281+
}
5282+
HConstant* cell_constant = Add<HConstant>(cell);
5283+
HLoadNamedField* instr;
5284+
if (field_maps == nullptr) {
5285+
instr = New<HLoadNamedField>(cell_constant, nullptr, access);
5286+
} else {
5287+
instr = New<HLoadNamedField>(cell_constant, nullptr, access, field_maps,
5288+
HType::HeapObject());
5289+
}
5290+
instr->ClearDependsOnFlag(kInobjectFields);
5291+
instr->SetDependsOnFlag(kGlobalVars);
5292+
return ast_context()->ReturnInstruction(instr, ast_id);
5293+
}
5294+
}
52425295

52435296
void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
52445297
DCHECK(!HasStackOverflow());
@@ -5287,57 +5340,9 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
52875340
}
52885341

52895342
LookupIterator it(global, variable->name(), LookupIterator::OWN);
5290-
GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD);
5291-
5292-
if (type == kUseCell) {
5293-
Handle<PropertyCell> cell = it.GetPropertyCell();
5294-
top_info()->dependencies()->AssumePropertyCell(cell);
5295-
auto cell_type = it.property_details().cell_type();
5296-
if (cell_type == PropertyCellType::kConstant ||
5297-
cell_type == PropertyCellType::kUndefined) {
5298-
Handle<Object> constant_object(cell->value(), isolate());
5299-
if (constant_object->IsConsString()) {
5300-
constant_object =
5301-
String::Flatten(Handle<String>::cast(constant_object));
5302-
}
5303-
HConstant* constant = New<HConstant>(constant_object);
5304-
return ast_context()->ReturnInstruction(constant, expr->id());
5305-
} else {
5306-
auto access = HObjectAccess::ForPropertyCellValue();
5307-
UniqueSet<Map>* field_maps = nullptr;
5308-
if (cell_type == PropertyCellType::kConstantType) {
5309-
switch (cell->GetConstantType()) {
5310-
case PropertyCellConstantType::kSmi:
5311-
access = access.WithRepresentation(Representation::Smi());
5312-
break;
5313-
case PropertyCellConstantType::kStableMap: {
5314-
// Check that the map really is stable. The heap object could
5315-
// have mutated without the cell updating state. In that case,
5316-
// make no promises about the loaded value except that it's a
5317-
// heap object.
5318-
access =
5319-
access.WithRepresentation(Representation::HeapObject());
5320-
Handle<Map> map(HeapObject::cast(cell->value())->map());
5321-
if (map->is_stable()) {
5322-
field_maps = new (zone())
5323-
UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone());
5324-
}
5325-
break;
5326-
}
5327-
}
5328-
}
5329-
HConstant* cell_constant = Add<HConstant>(cell);
5330-
HLoadNamedField* instr;
5331-
if (field_maps == nullptr) {
5332-
instr = New<HLoadNamedField>(cell_constant, nullptr, access);
5333-
} else {
5334-
instr = New<HLoadNamedField>(cell_constant, nullptr, access,
5335-
field_maps, HType::HeapObject());
5336-
}
5337-
instr->ClearDependsOnFlag(kInobjectFields);
5338-
instr->SetDependsOnFlag(kGlobalVars);
5339-
return ast_context()->ReturnInstruction(instr, expr->id());
5340-
}
5343+
if (CanInlineGlobalPropertyAccess(variable, &it, LOAD)) {
5344+
InlineGlobalPropertyLoad(&it, expr->id());
5345+
return;
53415346
} else {
53425347
Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate());
53435348

@@ -6441,6 +6446,67 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
64416446
expr->AssignmentId(), expr->IsUninitialized());
64426447
}
64436448

6449+
HInstruction* HOptimizedGraphBuilder::InlineGlobalPropertyStore(
6450+
LookupIterator* it, HValue* value, BailoutId ast_id) {
6451+
Handle<PropertyCell> cell = it->GetPropertyCell();
6452+
top_info()->dependencies()->AssumePropertyCell(cell);
6453+
auto cell_type = it->property_details().cell_type();
6454+
if (cell_type == PropertyCellType::kConstant ||
6455+
cell_type == PropertyCellType::kUndefined) {
6456+
Handle<Object> constant(cell->value(), isolate());
6457+
if (value->IsConstant()) {
6458+
HConstant* c_value = HConstant::cast(value);
6459+
if (!constant.is_identical_to(c_value->handle(isolate()))) {
6460+
Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6461+
Deoptimizer::EAGER);
6462+
}
6463+
} else {
6464+
HValue* c_constant = Add<HConstant>(constant);
6465+
IfBuilder builder(this);
6466+
if (constant->IsNumber()) {
6467+
builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ);
6468+
} else {
6469+
builder.If<HCompareObjectEqAndBranch>(value, c_constant);
6470+
}
6471+
builder.Then();
6472+
builder.Else();
6473+
Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6474+
Deoptimizer::EAGER);
6475+
builder.End();
6476+
}
6477+
}
6478+
HConstant* cell_constant = Add<HConstant>(cell);
6479+
auto access = HObjectAccess::ForPropertyCellValue();
6480+
if (cell_type == PropertyCellType::kConstantType) {
6481+
switch (cell->GetConstantType()) {
6482+
case PropertyCellConstantType::kSmi:
6483+
access = access.WithRepresentation(Representation::Smi());
6484+
break;
6485+
case PropertyCellConstantType::kStableMap: {
6486+
// First check that the previous value of the {cell} still has the
6487+
// map that we are about to check the new {value} for. If not, then
6488+
// the stable map assumption was invalidated and we cannot continue
6489+
// with the optimized code.
6490+
Handle<HeapObject> cell_value(HeapObject::cast(cell->value()));
6491+
Handle<Map> cell_value_map(cell_value->map());
6492+
if (!cell_value_map->is_stable()) {
6493+
Bailout(kUnstableConstantTypeHeapObject);
6494+
return nullptr;
6495+
}
6496+
top_info()->dependencies()->AssumeMapStable(cell_value_map);
6497+
// Now check that the new {value} is a HeapObject with the same map
6498+
Add<HCheckHeapObject>(value);
6499+
value = Add<HCheckMaps>(value, cell_value_map);
6500+
access = access.WithRepresentation(Representation::HeapObject());
6501+
break;
6502+
}
6503+
}
6504+
}
6505+
HInstruction* instr = New<HStoreNamedField>(cell_constant, access, value);
6506+
instr->ClearChangesFlag(kInobjectFields);
6507+
instr->SetChangesFlag(kGlobalVars);
6508+
return instr;
6509+
}
64446510

64456511
// Because not every expression has a position and there is not common
64466512
// superclass of Assignment and CountOperation, we cannot just pass the
@@ -6481,64 +6547,10 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
64816547
}
64826548

64836549
LookupIterator it(global, var->name(), LookupIterator::OWN);
6484-
GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE);
6485-
if (type == kUseCell) {
6486-
Handle<PropertyCell> cell = it.GetPropertyCell();
6487-
top_info()->dependencies()->AssumePropertyCell(cell);
6488-
auto cell_type = it.property_details().cell_type();
6489-
if (cell_type == PropertyCellType::kConstant ||
6490-
cell_type == PropertyCellType::kUndefined) {
6491-
Handle<Object> constant(cell->value(), isolate());
6492-
if (value->IsConstant()) {
6493-
HConstant* c_value = HConstant::cast(value);
6494-
if (!constant.is_identical_to(c_value->handle(isolate()))) {
6495-
Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6496-
Deoptimizer::EAGER);
6497-
}
6498-
} else {
6499-
HValue* c_constant = Add<HConstant>(constant);
6500-
IfBuilder builder(this);
6501-
if (constant->IsNumber()) {
6502-
builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ);
6503-
} else {
6504-
builder.If<HCompareObjectEqAndBranch>(value, c_constant);
6505-
}
6506-
builder.Then();
6507-
builder.Else();
6508-
Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6509-
Deoptimizer::EAGER);
6510-
builder.End();
6511-
}
6512-
}
6513-
HConstant* cell_constant = Add<HConstant>(cell);
6514-
auto access = HObjectAccess::ForPropertyCellValue();
6515-
if (cell_type == PropertyCellType::kConstantType) {
6516-
switch (cell->GetConstantType()) {
6517-
case PropertyCellConstantType::kSmi:
6518-
access = access.WithRepresentation(Representation::Smi());
6519-
break;
6520-
case PropertyCellConstantType::kStableMap: {
6521-
// First check that the previous value of the {cell} still has the
6522-
// map that we are about to check the new {value} for. If not, then
6523-
// the stable map assumption was invalidated and we cannot continue
6524-
// with the optimized code.
6525-
Handle<HeapObject> cell_value(HeapObject::cast(cell->value()));
6526-
Handle<Map> cell_value_map(cell_value->map());
6527-
if (!cell_value_map->is_stable()) {
6528-
return Bailout(kUnstableConstantTypeHeapObject);
6529-
}
6530-
top_info()->dependencies()->AssumeMapStable(cell_value_map);
6531-
// Now check that the new {value} is a HeapObject with the same map.
6532-
Add<HCheckHeapObject>(value);
6533-
value = Add<HCheckMaps>(value, cell_value_map);
6534-
access = access.WithRepresentation(Representation::HeapObject());
6535-
break;
6536-
}
6537-
}
6538-
}
6539-
HInstruction* instr = Add<HStoreNamedField>(cell_constant, access, value);
6540-
instr->ClearChangesFlag(kInobjectFields);
6541-
instr->SetChangesFlag(kGlobalVars);
6550+
if (CanInlineGlobalPropertyAccess(var, &it, STORE)) {
6551+
HInstruction* instr = InlineGlobalPropertyStore(&it, value, ast_id);
6552+
if (!instr) return;
6553+
AddInstruction(instr);
65426554
if (instr->HasObservableSideEffects()) {
65436555
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
65446556
}
@@ -7460,7 +7472,35 @@ HValue* HOptimizedGraphBuilder::BuildNamedAccess(
74607472
ComputeReceiverTypes(expr, object, &maps, this);
74617473
DCHECK(maps != NULL);
74627474

7475+
// Check for special case: Access via a single map to the global proxy
7476+
// can also be handled monomorphically.
74637477
if (maps->length() > 0) {
7478+
Handle<Object> map_constructor =
7479+
handle(maps->first()->GetConstructor(), isolate());
7480+
if (map_constructor->IsJSFunction()) {
7481+
Handle<Context> map_context =
7482+
handle(Handle<JSFunction>::cast(map_constructor)->context());
7483+
Handle<Context> current_context(current_info()->context());
7484+
bool is_same_context_global_proxy_access =
7485+
maps->length() == 1 && // >1 map => fallback to polymorphic
7486+
maps->first()->IsJSGlobalProxyMap() &&
7487+
(*map_context == *current_context);
7488+
if (is_same_context_global_proxy_access) {
7489+
Handle<JSGlobalObject> global_object(current_info()->global_object());
7490+
LookupIterator it(global_object, name, LookupIterator::OWN);
7491+
if (CanInlineGlobalPropertyAccess(&it, access)) {
7492+
BuildCheckHeapObject(object);
7493+
Add<HCheckMaps>(object, maps);
7494+
if (access == LOAD) {
7495+
InlineGlobalPropertyLoad(&it, expr->id());
7496+
return nullptr;
7497+
} else {
7498+
return InlineGlobalPropertyStore(&it, value, expr->id());
7499+
}
7500+
}
7501+
}
7502+
}
7503+
74647504
PropertyAccessInfo info(this, access, maps->first(), name);
74657505
if (!info.CanAccessAsMonomorphic(maps)) {
74667506
HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id,

src/crankshaft/hydrogen.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2333,13 +2333,15 @@ class HOptimizedGraphBuilder : public HGraphBuilder,
23332333
#undef DECLARE_VISIT
23342334

23352335
private:
2336-
// Helpers for flow graph construction.
2337-
enum GlobalPropertyAccess {
2338-
kUseCell,
2339-
kUseGeneric
2340-
};
2341-
GlobalPropertyAccess LookupGlobalProperty(Variable* var, LookupIterator* it,
2342-
PropertyAccessType access_type);
2336+
bool CanInlineGlobalPropertyAccess(Variable* var, LookupIterator* it,
2337+
PropertyAccessType access_type);
2338+
2339+
bool CanInlineGlobalPropertyAccess(LookupIterator* it,
2340+
PropertyAccessType access_type);
2341+
2342+
void InlineGlobalPropertyLoad(LookupIterator* it, BailoutId ast_id);
2343+
HInstruction* InlineGlobalPropertyStore(LookupIterator* it, HValue* value,
2344+
BailoutId ast_id);
23432345

23442346
void EnsureArgumentsArePushedForAccess();
23452347
bool TryArgumentsAccess(Property* expr);

0 commit comments

Comments
 (0)