Skip to content

Commit 9526189

Browse files
committed
ScopeNameUsage merge dicts into a single big one
and change it to use a unordered_map because it uses less memory in this case and is faster (I assume because it does not have align the key value tuples) saves about 10% of peak memory on django
1 parent e21a0dc commit 9526189

File tree

1 file changed

+82
-50
lines changed

1 file changed

+82
-50
lines changed

src/analysis/scoping_analysis.cpp

Lines changed: 82 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -203,23 +203,37 @@ class EvalExprScopeInfo : public ScopeInfo {
203203
InternedString internString(llvm::StringRef s) override { abort(); }
204204
};
205205

206+
struct ScopeNameUsageEntry {
207+
// Properties determined from crawling the scope:
208+
unsigned char read : 1;
209+
unsigned char written : 1;
210+
unsigned char forced_globals : 1;
211+
unsigned char params : 1;
212+
213+
// Properties determined by looking at other scopes as well:
214+
unsigned char referenced_from_nested : 1;
215+
unsigned char got_from_closure : 1;
216+
unsigned char passthrough_accesses : 1; // what names a child scope accesses a name from a parent scope
217+
218+
ScopeNameUsageEntry()
219+
: read(0),
220+
written(0),
221+
forced_globals(0),
222+
params(0),
223+
referenced_from_nested(0),
224+
got_from_closure(0),
225+
passthrough_accesses(0) {}
226+
};
227+
206228
struct ScopingAnalysis::ScopeNameUsage {
207229
AST* node;
208230
ScopeNameUsage* parent;
209231
llvm::StringRef private_name;
210232
ScopingAnalysis* scoping;
211233

212-
// Properties determined from crawling the scope:
213-
StrSet read;
214-
StrSet written;
215-
StrSet forced_globals;
216-
StrSet params;
217-
std::vector<AST_Name*> del_name_nodes;
234+
std::unordered_map<InternedString, ScopeNameUsageEntry> results;
218235

219-
// Properties determined by looking at other scopes as well:
220-
StrSet referenced_from_nested;
221-
StrSet got_from_closure;
222-
StrSet passthrough_accesses; // what names a child scope accesses a name from a parent scope
236+
std::vector<AST_Name*> del_name_nodes;
223237

224238
// `import *` and `exec` both force the scope to use the NAME lookup
225239
// However, this is not allowed to happen (a SyntaxError) if the scope has
@@ -251,12 +265,12 @@ struct ScopingAnalysis::ScopeNameUsage {
251265
AST_ClassDef* classdef = ast_cast<AST_ClassDef>(node);
252266

253267
// classes have an implicit write to "__module__"
254-
written.insert(scoping->getInternedStrings().get("__module__"));
268+
results[scoping->getInternedStrings().get("__module__")].written = 1;
255269

256270
if (classdef->body.size() && classdef->body[0]->type == AST_TYPE::Expr) {
257271
AST_Expr* first_expr = ast_cast<AST_Expr>(classdef->body[0]);
258272
if (first_expr->value->type == AST_TYPE::Str) {
259-
written.insert(scoping->getInternedStrings().get("__doc__"));
273+
results[scoping->getInternedStrings().get("__doc__")].written = 1;
260274
}
261275
}
262276
}
@@ -273,8 +287,10 @@ struct ScopingAnalysis::ScopeNameUsage {
273287
void dump() {
274288
#define DUMP(n) \
275289
printf(STRINGIFY(n) ":\n"); \
276-
for (auto s : n) { \
277-
printf("%s\n", s.c_str()); \
290+
for (auto s : results) { \
291+
if (!s.second.n) \
292+
continue; \
293+
printf("%s\n", s.first.c_str()); \
278294
}
279295

280296
DUMP(read);
@@ -300,6 +316,8 @@ class ScopeInfoBase : public ScopeInfo {
300316
bool allDerefVarsAndInfoCached;
301317

302318
bool globals_from_module;
319+
bool takes_closure = false;
320+
bool passthrough_accesses = false;
303321

304322
public:
305323
ScopeInfoBase(ScopeInfo* parent, ScopingAnalysis::ScopeNameUsage* usage, AST* ast, bool usesNameLookup,
@@ -313,45 +331,54 @@ class ScopeInfoBase : public ScopeInfo {
313331
assert(usage);
314332
assert(ast);
315333

334+
bool got_from_closure = false;
335+
std::vector<InternedString> referenced_from_nested_sorted;
336+
for (auto&& r : usage->results) {
337+
if (r.second.referenced_from_nested)
338+
referenced_from_nested_sorted.push_back(r.first);
339+
got_from_closure = got_from_closure || r.second.got_from_closure;
340+
passthrough_accesses = passthrough_accesses || r.second.passthrough_accesses;
341+
}
342+
316343
// Sort the entries by name to make the order deterministic.
317-
std::vector<InternedString> referenced_from_nested_sorted(usage->referenced_from_nested.begin(),
318-
usage->referenced_from_nested.end());
319344
std::sort(referenced_from_nested_sorted.begin(), referenced_from_nested_sorted.end());
320345
int i = 0;
321346
for (auto& p : referenced_from_nested_sorted) {
322347
closure_offsets[p] = i;
323348
i++;
324349
}
350+
351+
takes_closure = got_from_closure || passthrough_accesses;
325352
}
326353

327354
~ScopeInfoBase() override { delete this->usage; }
328355

329356
ScopeInfo* getParent() override { return parent; }
330357

331-
bool createsClosure() override { return usage->referenced_from_nested.size() > 0; }
358+
bool createsClosure() override { return closure_offsets.size() > 0; }
332359

333-
bool takesClosure() override {
334-
return usage->got_from_closure.size() > 0 || usage->passthrough_accesses.size() > 0;
335-
}
360+
bool takesClosure() override { return takes_closure; }
336361

337-
bool passesThroughClosure() override { return usage->passthrough_accesses.size() > 0 && !createsClosure(); }
362+
bool passesThroughClosure() override { return passthrough_accesses && !createsClosure(); }
338363

339364
VarScopeType getScopeTypeOfName(InternedString name) override {
340365
if (name.isCompilerCreatedName())
341366
return VarScopeType::FAST;
342367

343-
if (usage->forced_globals.count(name) > 0)
368+
auto it = usage->results.find(name);
369+
bool found_name = it != usage->results.end();
370+
if (found_name && it->second.forced_globals)
344371
return VarScopeType::GLOBAL;
345372

346-
if (usage->got_from_closure.count(name) > 0)
373+
if (found_name && it->second.got_from_closure)
347374
return VarScopeType::DEREF;
348375

349376
if (usesNameLookup_) {
350377
return VarScopeType::NAME;
351378
} else {
352-
if (usage->written.count(name) == 0)
379+
if (!found_name || !it->second.written)
353380
return VarScopeType::GLOBAL;
354-
else if (usage->referenced_from_nested.count(name) > 0)
381+
else if (found_name && it->second.referenced_from_nested)
355382
return VarScopeType::CLOSURE;
356383
else
357384
return VarScopeType::FAST;
@@ -409,16 +436,14 @@ class ScopeInfoBase : public ScopeInfo {
409436

410437
// Get all the variables that we need to return: any variable from the
411438
// passed-in closure that is accessed in this scope or in a child scope.
412-
StrSet allDerefs = usage->got_from_closure;
413-
for (InternedString name : usage->passthrough_accesses) {
414-
if (allDerefs.find(name) != allDerefs.end()) {
415-
allDerefs.insert(name);
416-
}
417-
}
418-
419-
// Call `getDerefInfo` on all of these variables and put the results in
420-
// `allDerefVarsAndInfo`
421-
for (InternedString name : allDerefs) {
439+
for (auto&& r : usage->results) {
440+
bool is_deref = r.second.got_from_closure || r.second.passthrough_accesses;
441+
if (!is_deref)
442+
continue;
443+
444+
auto&& name = r.first;
445+
// Call `getDerefInfo` on all of these variables and put the results in
446+
// `allDerefVarsAndInfo`
422447
allDerefVarsAndInfo.push_back({ name, getDerefInfo(name) });
423448
}
424449

@@ -459,16 +484,17 @@ class NameCollectorVisitor : public ASTVisitor {
459484
public:
460485
void doWrite(InternedString name) {
461486
assert(name == mangleName(name, cur->private_name, scoping->getInternedStrings()));
462-
cur->read.insert(name);
463-
cur->written.insert(name);
487+
auto& r = cur->results[name];
488+
r.read = 1;
489+
r.written = 1;
464490
if (this->currently_visiting_functiondef_args) {
465-
cur->params.insert(name);
491+
r.params = 1;
466492
}
467493
}
468494

469495
void doRead(InternedString name) {
470496
assert(name == mangleName(name, cur->private_name, scoping->getInternedStrings()));
471-
cur->read.insert(name);
497+
cur->results[name].read = 1;
472498
}
473499

474500
void doDel(AST_Name* node) { cur->del_name_nodes.push_back(node); }
@@ -557,11 +583,12 @@ class NameCollectorVisitor : public ASTVisitor {
557583
bool visit_global(AST_Global* node) override {
558584
for (int i = 0; i < node->names.size(); i++) {
559585
mangleNameInPlace(node->names[i], cur->private_name, scoping->getInternedStrings());
560-
if (cur->params.find(node->names[i]) != cur->params.end()) {
586+
auto& r = cur->results[node->names[i]];
587+
if (r.params) {
561588
// Throw an exception if a name is both declared global and a parameter
562589
raiseGlobalAndLocalException(node->names[i], this->orig_node);
563590
}
564-
cur->forced_globals.insert(node->names[i]);
591+
r.forced_globals = 1;
565592
}
566593
return true;
567594
}
@@ -788,30 +815,35 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
788815

789816
bool is_any_name_free = false;
790817

791-
for (const auto& name : usage->read) {
792-
if (usage->forced_globals.count(name))
818+
for (auto&& r : usage->results) {
819+
if (!r.second.read)
793820
continue;
794-
if (usage->written.count(name))
821+
if (r.second.forced_globals)
795822
continue;
823+
if (r.second.written)
824+
continue;
825+
826+
auto&& name = r.first;
796827

797828
bool is_name_free = true;
798829

799830
std::vector<ScopeNameUsage*> intermediate_parents;
800831

801832
ScopeNameUsage* parent = usage->parent;
802833
while (parent) {
834+
auto parent_result = parent->results.find(name);
803835
if (parent->node->type == AST_TYPE::ClassDef) {
804836
intermediate_parents.push_back(parent);
805837
parent = parent->parent;
806-
} else if (parent->forced_globals.count(name)) {
838+
} else if (parent_result != parent->results.end() && parent_result->second.forced_globals) {
807839
is_name_free = false;
808840
break;
809-
} else if (parent->written.count(name)) {
810-
usage->got_from_closure.insert(name);
811-
parent->referenced_from_nested.insert(name);
841+
} else if (parent_result != parent->results.end() && parent_result->second.written) {
842+
r.second.got_from_closure = 1;
843+
parent_result->second.referenced_from_nested = 1;
812844

813845
for (ScopeNameUsage* iparent : intermediate_parents) {
814-
iparent->passthrough_accesses.insert(name);
846+
iparent->results[name].passthrough_accesses = 1;
815847
}
816848

817849
break;
@@ -853,7 +885,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
853885
// `del` for closure variables. But it is, so, there you go:
854886
for (AST_Name* name_node : usage->del_name_nodes) {
855887
InternedString name = name_node->id;
856-
if (usage->referenced_from_nested.count(name) > 0) {
888+
if (usage->results.count(name) && usage->results[name].referenced_from_nested) {
857889
char buf[1024];
858890
snprintf(buf, sizeof(buf), "can not delete variable '%s' referenced in nested scope", name.c_str());
859891
assert(usage->node->type == AST_TYPE::FunctionDef);

0 commit comments

Comments
 (0)