Commit 325dbfeb authored by Kevin Modzelewski's avatar Kevin Modzelewski

Intern most codegen strings

Most importantly, intern all the strings we put into the AST* nodes.
(the AST_Module* owns them)

This should save us some memory, but it also improves performance pretty
substantially since now we can do string comparisons very cheaply.  Performance
of the interpreter tier is up by something like 30%, and JIT-compilation times
are down as well (though not by as much as I was hoping).

The overall effect on perf is more muted since we tier out of the interpreter
pretty quickly; to see more benefit, we'll have to retune the OSR/reopt thresholds.

For better or worse (mostly better IMO), the interned-ness is encoded in the type
system, and things will not automatically convert between an InternedString and
a std::string.  It means that this diff is quite large, but it also makes it a lot
more clear where we are making our string copies or have other room for optimization.
parent d3ba142d
......@@ -25,7 +25,7 @@ namespace pyston {
template <typename T> class BBAnalyzer {
public:
typedef std::unordered_map<std::string, T> Map;
typedef std::unordered_map<InternedString, T> Map;
typedef std::unordered_map<CFGBlock*, Map> AllMap;
virtual ~BBAnalyzer() {}
......
......@@ -51,27 +51,23 @@ private:
};
std::unordered_set<AST_Name*> kills;
std::unordered_map<int, AST_Name*> last_uses;
std::unordered_map<InternedString, AST_Name*> last_uses;
std::unordered_map<int, Status> statuses;
std::unordered_map<InternedString, Status> statuses;
LivenessAnalysis* analysis;
void _doLoad(const std::string& name, AST_Name* node) {
int id = analysis->getStringIndex(name);
Status& status = statuses[id];
void _doLoad(InternedString name, AST_Name* node) {
Status& status = statuses[name];
status.addUsage(Status::USED);
last_uses[id] = node;
last_uses[name] = node;
}
void _doStore(const std::string& name) {
int id = analysis->getStringIndex(name);
Status& status = statuses[id];
void _doStore(InternedString name) {
Status& status = statuses[name];
status.addUsage(Status::DEFINED);
auto it = last_uses.find(id);
auto it = last_uses.find(name);
if (it != last_uses.end()) {
kills.insert(it->second);
last_uses.erase(it);
......@@ -81,9 +77,9 @@ private:
public:
LivenessBBVisitor(LivenessAnalysis* analysis) : analysis(analysis) {}
bool firstIsUse(int idx) { return statuses[idx].first == Status::USED; }
bool firstIsUse(InternedString name) { return statuses[name].first == Status::USED; }
bool firstIsDef(int idx) { return statuses[idx].first == Status::DEFINED; }
bool firstIsDef(InternedString name) { return statuses[name].first == Status::DEFINED; }
bool isKilledAt(AST_Name* node, bool is_live_at_end) {
if (kills.count(node))
......@@ -93,7 +89,7 @@ public:
// even though we weren't able to determine that in a single
// pass
if (!is_live_at_end) {
auto it = last_uses.find(analysis->getStringIndex(node->id));
auto it = last_uses.find(node->id);
if (it != last_uses.end() && node == it->second)
return true;
}
......@@ -141,23 +137,15 @@ public:
return true;
}
bool visit_alias(AST_alias* node) {
const std::string* name = &node->name;
if (node->asname.size())
name = &node->asname;
InternedString name = node->name;
if (node->asname.str().size())
name = node->asname;
_doStore(*name);
_doStore(name);
return true;
}
};
int LivenessAnalysis::getStringIndex(const std::string& s) {
int& r = string_index_map[s];
if (r == 0) {
r = string_index_map.size(); // includes the '0' entry we just put in there
}
return r;
}
LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg) {
Timer _t("LivenessAnalysis()", 10);
......@@ -174,31 +162,30 @@ LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg) {
}
bool LivenessAnalysis::isKill(AST_Name* node, CFGBlock* parent_block) {
if (node->id[0] != '#')
if (node->id.str()[0] != '#')
return false;
return liveness_cache[parent_block]->isKilledAt(node, isLiveAtEnd(node->id, parent_block));
}
bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) {
bool LivenessAnalysis::isLiveAtEnd(InternedString name, CFGBlock* block) {
Timer _t("LivenessAnalysis()", 10);
if (name[0] != '#')
if (name.str()[0] != '#')
return true;
if (block->successors.size() == 0)
return false;
int idx = getStringIndex(name);
if (!result_cache.count(idx)) {
std::unordered_map<CFGBlock*, bool>& map = result_cache[idx];
if (!result_cache.count(name)) {
std::unordered_map<CFGBlock*, bool>& map = result_cache[name];
// Approach:
// - Find all uses (blocks where the status is USED)
// - Trace backwards, marking all blocks as live-at-end
// - If we hit a block that is DEFINED, stop
for (CFGBlock* b : cfg->blocks) {
if (!liveness_cache[b]->firstIsUse(idx))
if (!liveness_cache[b]->firstIsUse(name))
continue;
std::deque<CFGBlock*> q;
......@@ -214,7 +201,7 @@ bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) {
continue;
map[thisblock] = true;
if (!liveness_cache[thisblock]->firstIsDef(idx)) {
if (!liveness_cache[thisblock]->firstIsDef(name)) {
for (CFGBlock* pred : thisblock->predecessors) {
q.push_back(pred);
}
......@@ -227,7 +214,7 @@ bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) {
static StatCounter us_liveness("us_compiling_analysis_liveness");
us_liveness.log(_t.end());
return result_cache[idx][block];
return result_cache[name][block];
}
class DefinednessBBAnalyzer : public BBAnalyzer<DefinednessAnalysis::DefinitionLevel> {
......@@ -259,7 +246,7 @@ private:
typedef DefinednessBBAnalyzer::Map Map;
Map& state;
void _doSet(const std::string& s) { state[s] = DefinednessAnalysis::Defined; }
void _doSet(InternedString s) { state[s] = DefinednessAnalysis::Defined; }
void _doSet(AST* t) {
switch (t->type) {
......@@ -309,11 +296,11 @@ public:
}
virtual bool visit_alias(AST_alias* node) {
const std::string* name = &node->name;
if (node->asname.size())
name = &node->asname;
InternedString name = node->name;
if (node->asname.str().size())
name = node->asname;
_doSet(*name);
_doSet(name);
return true;
}
virtual bool visit_import(AST_Import* node) { return false; }
......@@ -327,9 +314,9 @@ public:
}
virtual bool visit_arguments(AST_arguments* node) {
if (node->kwarg.size())
if (node->kwarg.str().size())
_doSet(node->kwarg);
if (node->vararg.size())
if (node->vararg.str().size())
_doSet(node->vararg);
for (int i = 0; i < node->args.size(); i++) {
_doSet(node->args[i]);
......@@ -346,10 +333,10 @@ void DefinednessBBAnalyzer::processBB(Map& starting, CFGBlock* block) const {
if (block == cfg->getStartingBlock() && arg_names.args) {
for (auto e : (*arg_names.args))
visitor._doSet(e);
if (arg_names.vararg->size())
visitor._doSet(*arg_names.vararg);
if (arg_names.kwarg->size())
visitor._doSet(*arg_names.kwarg);
if (arg_names.vararg.str().size())
visitor._doSet(arg_names.vararg);
if (arg_names.kwarg.str().size())
visitor._doSet(arg_names.kwarg);
}
for (int i = 0; i < block->body.size(); i++) {
......@@ -386,8 +373,8 @@ DefinednessAnalysis::DefinednessAnalysis(const SourceInfo::ArgNames& arg_names,
us_definedness.log(_t.end());
}
DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAtEnd(const std::string& name, CFGBlock* block) {
std::unordered_map<std::string, DefinitionLevel>& map = results[block];
DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAtEnd(InternedString name, CFGBlock* block) {
auto& map = results[block];
if (map.count(name) == 0)
return Undefined;
return map[name];
......@@ -436,13 +423,13 @@ const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredFor(CFGBlock* block)
return required_phis[block];
}
bool PhiAnalysis::isRequired(const std::string& name, CFGBlock* block) {
assert(!startswith(name, "!"));
bool PhiAnalysis::isRequired(InternedString name, CFGBlock* block) {
assert(!startswith(name.str(), "!"));
return required_phis[block].count(name) != 0;
}
bool PhiAnalysis::isRequiredAfter(const std::string& name, CFGBlock* block) {
assert(!startswith(name, "!"));
bool PhiAnalysis::isRequiredAfter(InternedString name, CFGBlock* block) {
assert(!startswith(name.str(), "!"));
// If there are multiple successors, then none of them are allowed
// to require any phi nodes
if (block->successors.size() != 1)
......@@ -452,8 +439,8 @@ bool PhiAnalysis::isRequiredAfter(const std::string& name, CFGBlock* block) {
return isRequired(name, block->successors[0]);
}
bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block) {
assert(!startswith(name, "!"));
bool PhiAnalysis::isPotentiallyUndefinedAfter(InternedString name, CFGBlock* block) {
assert(!startswith(name.str(), "!"));
if (block->successors.size() != 1)
return false;
......@@ -461,8 +448,8 @@ bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string& name, CFGBlock*
return isPotentiallyUndefinedAt(name, block->successors[0]);
}
bool PhiAnalysis::isPotentiallyUndefinedAt(const std::string& name, CFGBlock* block) {
assert(!startswith(name, "!"));
bool PhiAnalysis::isPotentiallyUndefinedAt(InternedString name, CFGBlock* block) {
assert(!startswith(name.str(), "!"));
for (CFGBlock* pred : block->predecessors) {
DefinednessAnalysis::DefinitionLevel dlevel = definedness.isDefinedAtEnd(name, pred);
......
......@@ -19,6 +19,7 @@
#include <unordered_map>
#include <unordered_set>
#include "core/stringpool.h"
#include "core/types.h"
namespace pyston {
......@@ -39,17 +40,7 @@ private:
typedef std::unordered_map<CFGBlock*, std::unique_ptr<LivenessBBVisitor>> LivenessCacheMap;
LivenessCacheMap liveness_cache;
std::unordered_map<int, std::unordered_map<CFGBlock*, bool>> result_cache;
// Map strings to unique indices. For a given CFG, the set of strings should be fairly small
// (a constant fraction max of the CFG itself), so just store all of them. The theory is that
// for any particular name, we will do many lookups on it in different hash tables, and by
// converting to a string only once, the extra hashtable lookup will be profitable since it
// can make all the rest faster (int hashes vs string hashes).
//
// Haven't validated this, though.
std::unordered_map<std::string, int> string_index_map;
int getStringIndex(const std::string& s);
std::unordered_map<InternedString, std::unordered_map<CFGBlock*, bool>> result_cache;
public:
LivenessAnalysis(CFG* cfg);
......@@ -57,7 +48,7 @@ public:
// we don't keep track of node->parent_block relationships, so you have to pass both:
bool isKill(AST_Name* node, CFGBlock* parent_block);
bool isLiveAtEnd(const std::string& name, CFGBlock* block);
bool isLiveAtEnd(InternedString name, CFGBlock* block);
};
class DefinednessAnalysis {
......@@ -67,22 +58,22 @@ public:
PotentiallyDefined,
Defined,
};
typedef std::unordered_set<std::string> RequiredSet;
typedef std::unordered_set<InternedString> RequiredSet;
private:
std::unordered_map<CFGBlock*, std::unordered_map<std::string, DefinitionLevel>> results;
std::unordered_map<CFGBlock*, std::unordered_map<InternedString, DefinitionLevel>> results;
std::unordered_map<CFGBlock*, const RequiredSet> defined_at_end;
ScopeInfo* scope_info;
public:
DefinednessAnalysis(const SourceInfo::ArgNames& args, CFG* cfg, ScopeInfo* scope_info);
DefinitionLevel isDefinedAtEnd(const std::string& name, CFGBlock* block);
DefinitionLevel isDefinedAtEnd(InternedString name, CFGBlock* block);
const RequiredSet& getDefinedNamesAtEnd(CFGBlock* block);
};
class PhiAnalysis {
public:
typedef std::unordered_set<std::string> RequiredSet;
typedef std::unordered_set<InternedString> RequiredSet;
DefinednessAnalysis definedness;
......@@ -93,12 +84,12 @@ private:
public:
PhiAnalysis(const SourceInfo::ArgNames&, CFG* cfg, LivenessAnalysis* liveness, ScopeInfo* scope_info);
bool isRequired(const std::string& name, CFGBlock* block);
bool isRequiredAfter(const std::string& name, CFGBlock* block);
bool isRequired(InternedString name, CFGBlock* block);
bool isRequiredAfter(InternedString name, CFGBlock* block);
const RequiredSet& getAllRequiredAfter(CFGBlock* block);
const RequiredSet& getAllRequiredFor(CFGBlock* block);
bool isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block);
bool isPotentiallyUndefinedAt(const std::string& name, CFGBlock* block);
bool isPotentiallyUndefinedAfter(InternedString name, CFGBlock* block);
bool isPotentiallyUndefinedAt(InternedString name, CFGBlock* block);
};
LivenessAnalysis* computeLivenessInfo(CFG*);
......
......@@ -49,15 +49,16 @@ bool containsYield(AST* ast) {
return visitor.containsYield;
}
static void mangleNameInPlace(std::string& id, const std::string* private_name) {
static void mangleNameInPlace(InternedString& id, const std::string* private_name,
InternedStringPool& interned_strings) {
if (!private_name)
return;
int len = id.size();
if (len < 2 || id[0] != '_' || id[1] != '_')
int len = id.str().size();
if (len < 2 || id.str()[0] != '_' || id.str()[1] != '_')
return;
if ((id[len - 2] == '_' && id[len - 1] == '_') || id.find('.') != std::string::npos)
if ((id.str()[len - 2] == '_' && id.str()[len - 1] == '_') || id.str().find('.') != std::string::npos)
return;
const char* p = private_name->c_str();
......@@ -68,17 +69,18 @@ static void mangleNameInPlace(std::string& id, const std::string* private_name)
if (*p == '\0')
return;
id = "_" + (p + id);
id = interned_strings.get("_" + (p + id.str()));
}
static std::string mangleName(const std::string& id, const std::string* private_name) {
std::string rtn(id);
mangleNameInPlace(rtn, private_name);
static InternedString mangleName(InternedString id, const std::string* private_name,
InternedStringPool& interned_strings) {
InternedString rtn(id);
mangleNameInPlace(rtn, private_name, interned_strings);
return rtn;
}
static bool isCompilerCreatedName(const std::string& name) {
return name[0] == '!' || name[0] == '#';
static bool isCompilerCreatedName(InternedString name) {
return name.str()[0] == '!' || name.str()[0] == '#';
}
class ModuleScopeInfo : public ScopeInfo {
......@@ -91,27 +93,26 @@ public:
bool passesThroughClosure() override { return false; }
bool refersToGlobal(const std::string& name) override {
bool refersToGlobal(InternedString name) override {
if (isCompilerCreatedName(name))
return false;
// assert(name[0] != '#' && "should test this");
return true;
}
bool refersToClosure(const std::string& name) override { return false; }
bool saveInClosure(const std::string& name) override { return false; }
bool refersToClosure(InternedString name) override { return false; }
bool saveInClosure(InternedString name) override { return false; }
const std::unordered_set<std::string>& getClassDefLocalNames() override { RELEASE_ASSERT(0, ""); }
std::string mangleName(const std::string& id) override { return id; }
InternedString mangleName(InternedString id) override { return id; }
};
struct ScopingAnalysis::ScopeNameUsage {
AST* node;
ScopeNameUsage* parent;
const std::string* private_name;
ScopingAnalysis* scoping;
typedef std::unordered_set<std::string> StrSet;
typedef std::unordered_set<InternedString> StrSet;
// Properties determined from crawling the scope:
StrSet read;
......@@ -123,29 +124,46 @@ struct ScopingAnalysis::ScopeNameUsage {
StrSet got_from_closure;
StrSet passthrough_accesses; // what names a child scope accesses a name from a parent scope
ScopeNameUsage(AST* node, ScopeNameUsage* parent) : node(node), parent(parent) {
ScopeNameUsage(AST* node, ScopeNameUsage* parent, ScopingAnalysis* scoping)
: node(node), parent(parent), scoping(scoping) {
if (node->type == AST_TYPE::ClassDef) {
AST_ClassDef* classdef = ast_cast<AST_ClassDef>(node);
// classes have an implicit write to "__module__"
written.insert("__module__");
written.insert(scoping->getInternedStrings().get("__module__"));
if (classdef->body.size() && classdef->body[0]->type == AST_TYPE::Expr) {
AST_Expr* first_expr = ast_cast<AST_Expr>(classdef->body[0]);
if (first_expr->value->type == AST_TYPE::Str) {
written.insert("__doc__");
written.insert(scoping->getInternedStrings().get("__doc__"));
}
}
}
if (node->type == AST_TYPE::ClassDef) {
private_name = &ast_cast<AST_ClassDef>(node)->name;
private_name = &ast_cast<AST_ClassDef>(node)->name.str();
} else if (parent) {
private_name = parent->private_name;
} else {
private_name = NULL;
}
}
void dump() {
#define DUMP(n) \
printf(STRINGIFY(n) ":\n"); \
for (auto s : n) { \
printf("%s\n", s.c_str()); \
}
DUMP(read);
DUMP(written);
DUMP(forced_globals);
printf("\n");
DUMP(referenced_from_nested);
DUMP(got_from_closure);
DUMP(passthrough_accesses);
}
};
class ScopeInfoBase : public ScopeInfo {
......@@ -174,34 +192,33 @@ public:
bool passesThroughClosure() override { return usage->passthrough_accesses.size() > 0 && !createsClosure(); }
bool refersToGlobal(const std::string& name) override {
bool refersToGlobal(InternedString name) override {
// HAX
if (isCompilerCreatedName(name))
return false;
if (usage->forced_globals.count(name))
return true;
if (name.c_str() != name.c_str())
usage->dump();
return usage->written.count(name) == 0 && usage->got_from_closure.count(name) == 0;
}
bool refersToClosure(const std::string& name) override {
bool refersToClosure(InternedString name) override {
// HAX
if (isCompilerCreatedName(name))
return false;
return usage->got_from_closure.count(name) != 0;
}
bool saveInClosure(const std::string& name) override {
bool saveInClosure(InternedString name) override {
// HAX
if (isCompilerCreatedName(name))
return false;
return usage->referenced_from_nested.count(name) != 0;
}
const std::unordered_set<std::string>& getClassDefLocalNames() override {
RELEASE_ASSERT(usage->node->type == AST_TYPE::ClassDef, "");
return usage->written;
InternedString mangleName(const InternedString id) override {
return pyston::mangleName(id, usage->private_name, usage->scoping->getInternedStrings());
}
std::string mangleName(const std::string& id) override { return pyston::mangleName(id, usage->private_name); }
};
class NameCollectorVisitor : public ASTVisitor {
......@@ -209,26 +226,28 @@ private:
AST* orig_node;
ScopingAnalysis::NameUsageMap* map;
ScopingAnalysis::ScopeNameUsage* cur;
NameCollectorVisitor(AST* node, ScopingAnalysis::NameUsageMap* map) : orig_node(node), map(map) {
ScopingAnalysis* scoping;
NameCollectorVisitor(AST* node, ScopingAnalysis::NameUsageMap* map, ScopingAnalysis* scoping)
: orig_node(node), map(map), scoping(scoping) {
assert(map);
cur = (*map)[node];
assert(cur);
}
public:
void doWrite(const std::string& name) {
assert(name == mangleName(name, cur->private_name));
void doWrite(InternedString name) {
assert(name == mangleName(name, cur->private_name, scoping->getInternedStrings()));
cur->read.insert(name);
cur->written.insert(name);
}
void doRead(const std::string& name) {
assert(name == mangleName(name, cur->private_name));
void doRead(InternedString name) {
assert(name == mangleName(name, cur->private_name, scoping->getInternedStrings()));
cur->read.insert(name);
}
bool visit_name(AST_Name* node) override {
mangleNameInPlace(node->id, cur->private_name);
mangleNameInPlace(node->id, cur->private_name, scoping->getInternedStrings());
switch (node->ctx_type) {
case AST_TYPE::Load:
......@@ -298,7 +317,7 @@ public:
bool visit_global(AST_Global* node) override {
for (int i = 0; i < node->names.size(); i++) {
mangleNameInPlace(node->names[i], cur->private_name);
mangleNameInPlace(node->names[i], cur->private_name, scoping->getInternedStrings());
cur->forced_globals.insert(node->names[i]);
}
return true;
......@@ -318,9 +337,9 @@ public:
// TODO: this is one of very few places we don't mangle in place.
// The AST doesn't have a way of representing that the class name is the
// unmangled name but the name it gets stored as is the mangled name.
doWrite(mangleName(node->name, cur->private_name));
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur);
collect(node, map);
doWrite(mangleName(node->name, cur->private_name, scoping->getInternedStrings()));
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur, scoping);
collect(node, map, scoping);
return true;
}
}
......@@ -329,12 +348,12 @@ public:
if (node == orig_node) {
for (AST_expr* e : node->args->args)
e->accept(this);
if (node->args->vararg.size()) {
mangleNameInPlace(node->args->vararg, cur->private_name);
if (node->args->vararg.str().size()) {
mangleNameInPlace(node->args->vararg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->vararg);
}
if (node->args->kwarg.size()) {
mangleNameInPlace(node->args->kwarg, cur->private_name);
if (node->args->kwarg.str().size()) {
mangleNameInPlace(node->args->kwarg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->kwarg);
}
for (AST_stmt* s : node->body)
......@@ -349,9 +368,9 @@ public:
// TODO: this is one of very few places we don't mangle in place.
// The AST doesn't have a way of representing that the class name is the
// unmangled name but the name it gets stored as is the mangled name.
doWrite(mangleName(node->name, cur->private_name));
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur);
collect(node, map);
doWrite(mangleName(node->name, cur->private_name, scoping->getInternedStrings()));
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur, scoping);
collect(node, map, scoping);
return true;
}
}
......@@ -369,8 +388,8 @@ public:
node->elt->accept(this);
} else {
node->generators[0]->iter->accept(this);
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur);
collect(node, map);
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur, scoping);
collect(node, map, scoping);
}
return true;
......@@ -380,20 +399,20 @@ public:
if (node == orig_node) {
for (AST_expr* e : node->args->args)
e->accept(this);
if (node->args->vararg.size()) {
mangleNameInPlace(node->args->vararg, cur->private_name);
if (node->args->vararg.str().size()) {
mangleNameInPlace(node->args->vararg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->vararg);
}
if (node->args->kwarg.size()) {
mangleNameInPlace(node->args->kwarg, cur->private_name);
if (node->args->kwarg.str().size()) {
mangleNameInPlace(node->args->kwarg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->kwarg);
}
node->body->accept(this);
} else {
for (auto* e : node->args->defaults)
e->accept(this);
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur);
collect(node, map);
(*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur, scoping);
collect(node, map, scoping);
}
return true;
......@@ -402,9 +421,9 @@ public:
bool visit_import(AST_Import* node) override {
for (int i = 0; i < node->names.size(); i++) {
AST_alias* alias = node->names[i];
mangleNameInPlace(alias->asname, cur->private_name);
mangleNameInPlace(alias->name, cur->private_name);
if (alias->asname.size())
mangleNameInPlace(alias->asname, cur->private_name, scoping->getInternedStrings());
mangleNameInPlace(alias->name, cur->private_name, scoping->getInternedStrings());
if (alias->asname.str().size())
doWrite(alias->asname);
else
doWrite(alias->name);
......@@ -415,9 +434,9 @@ public:
bool visit_importfrom(AST_ImportFrom* node) override {
for (int i = 0; i < node->names.size(); i++) {
AST_alias* alias = node->names[i];
mangleNameInPlace(alias->asname, cur->private_name);
mangleNameInPlace(alias->name, cur->private_name);
if (alias->asname.size())
mangleNameInPlace(alias->asname, cur->private_name, scoping->getInternedStrings());
mangleNameInPlace(alias->name, cur->private_name, scoping->getInternedStrings());
if (alias->asname.str().size())
doWrite(alias->asname);
else
doWrite(alias->name);
......@@ -425,11 +444,11 @@ public:
return true;
}
static void collect(AST* node, ScopingAnalysis::NameUsageMap* map) {
static void collect(AST* node, ScopingAnalysis::NameUsageMap* map, ScopingAnalysis* scoping) {
assert(map);
assert(map->count(node));
NameCollectorVisitor vis(node, map);
NameCollectorVisitor vis(node, map, scoping);
node->accept(&vis);
}
};
......@@ -525,10 +544,15 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
}
}
InternedStringPool& ScopingAnalysis::getInternedStrings() {
assert(parent_module);
return *parent_module->interned_strings.get();
}
ScopeInfo* ScopingAnalysis::analyzeSubtree(AST* node) {
NameUsageMap usages;
usages[node] = new ScopeNameUsage(node, NULL);
NameCollectorVisitor::collect(node, &usages);
usages[node] = new ScopeNameUsage(node, NULL, this);
NameCollectorVisitor::collect(node, &usages, this);
processNameUsages(&usages);
......@@ -566,7 +590,7 @@ ScopeInfo* ScopingAnalysis::getScopeInfoForNode(AST* node) {
return analyzeSubtree(node);
}
ScopingAnalysis::ScopingAnalysis(AST_Module* m) : parent_module(m) {
ScopingAnalysis::ScopingAnalysis(AST_Module* m) : parent_module(m), interned_strings(*m->interned_strings.get()) {
scopes[m] = new ModuleScopeInfo();
}
......
......@@ -16,6 +16,7 @@
#define PYSTON_ANALYSIS_SCOPINGANALYSIS_H
#include "core/common.h"
#include "core/stringpool.h"
namespace pyston {
......@@ -32,16 +33,11 @@ public:
virtual bool takesClosure() = 0;
virtual bool passesThroughClosure() = 0;
virtual bool refersToGlobal(const std::string& name) = 0;
virtual bool refersToClosure(const std::string& name) = 0;
virtual bool saveInClosure(const std::string& name) = 0;
virtual bool refersToGlobal(InternedString name) = 0;
virtual bool refersToClosure(InternedString name) = 0;
virtual bool saveInClosure(InternedString name) = 0;
// Get the names set within a classdef that should be forwarded on to
// the metaclass constructor.
// An error to call this on a non-classdef node.
virtual const std::unordered_set<std::string>& getClassDefLocalNames() = 0;
virtual std::string mangleName(const std::string& id) = 0;
virtual InternedString mangleName(InternedString id) = 0;
};
class ScopingAnalysis {
......@@ -52,6 +48,7 @@ public:
private:
std::unordered_map<AST*, ScopeInfo*> scopes;
AST_Module* parent_module;
InternedStringPool& interned_strings;
std::unordered_map<AST*, AST*> scope_replacements;
......@@ -70,6 +67,8 @@ public:
ScopingAnalysis(AST_Module* m);
ScopeInfo* getScopeInfoForNode(AST* node);
InternedStringPool& getInternedStrings();
};
ScopingAnalysis* runScopingAnalysis(AST_Module* m);
......
......@@ -36,17 +36,17 @@ namespace pyston {
class NullTypeAnalysis : public TypeAnalysis {
public:
ConcreteCompilerType* getTypeAtBlockStart(const std::string& name, CFGBlock* block) override;
ConcreteCompilerType* getTypeAtBlockEnd(const std::string& name, CFGBlock* block) override;
ConcreteCompilerType* getTypeAtBlockStart(InternedString name, CFGBlock* block) override;
ConcreteCompilerType* getTypeAtBlockEnd(InternedString name, CFGBlock* block) override;
BoxedClass* speculatedExprClass(AST_expr*) override { return NULL; }
};
ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockStart(const std::string& name, CFGBlock* block) {
ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockStart(InternedString name, CFGBlock* block) {
return UNKNOWN;
}
ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockEnd(const std::string& name, CFGBlock* block) {
ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockEnd(InternedString name, CFGBlock* block) {
assert(block->successors.size() > 0);
return getTypeAtBlockStart(name, block->successors[0]);
}
......@@ -68,7 +68,7 @@ static BoxedClass* simpleCallSpeculation(AST_Call* node, CompilerType* rtn_type,
return NULL;
}
if (node->func->type == AST_TYPE::Name && ast_cast<AST_Name>(node->func)->id == "xrange")
if (node->func->type == AST_TYPE::Name && ast_cast<AST_Name>(node->func)->id.str() == "xrange")
return xrange_cls;
// if (node->func->type == AST_TYPE::Attribute && ast_cast<AST_Attribute>(node->func)->attr == "dot")
......@@ -77,7 +77,7 @@ static BoxedClass* simpleCallSpeculation(AST_Call* node, CompilerType* rtn_type,
return NULL;
}
typedef std::unordered_map<std::string, CompilerType*> TypeMap;
typedef std::unordered_map<InternedString, CompilerType*> TypeMap;
typedef std::unordered_map<CFGBlock*, TypeMap> AllTypeMap;
typedef std::unordered_map<AST_expr*, CompilerType*> ExprTypeMap;
typedef std::unordered_map<AST_expr*, BoxedClass*> TypeSpeculations;
......@@ -140,7 +140,7 @@ private:
return rtn;
}
void _doSet(std::string target, CompilerType* t) {
void _doSet(InternedString target, CompilerType* t) {
if (t)
sym_table[target] = t;
}
......@@ -170,7 +170,7 @@ private:
void* visit_attribute(AST_Attribute* node) override {
CompilerType* t = getType(node->value);
CompilerType* rtn = t->getattrType(&node->attr, false);
CompilerType* rtn = t->getattrType(&node->attr.str(), false);
// if (speculation != TypeAnalysis::NONE && (node->attr == "x" || node->attr == "y" || node->attr == "z")) {
// rtn = processSpeculation(float_cls, node, rtn);
......@@ -192,7 +192,7 @@ private:
void* visit_clsattribute(AST_ClsAttribute* node) override {
CompilerType* t = getType(node->value);
CompilerType* rtn = t->getattrType(&node->attr, true);
CompilerType* rtn = t->getattrType(&node->attr.str(), true);
if (VERBOSITY() >= 2 && rtn == UNDEF) {
printf("Think %s.%s is undefined, at %d:%d\n", t->debugName().c_str(), node->attr.c_str(), node->lineno,
node->col_offset);
......@@ -288,9 +288,9 @@ private:
arg_types.push_back(getType(node->args[i]));
}
std::vector<std::pair<const std::string&, CompilerType*>> kw_types;
std::vector<std::pair<InternedString, CompilerType*>> kw_types;
for (AST_keyword* kw : node->keywords) {
kw_types.push_back(std::make_pair<const std::string&, CompilerType*>(kw->arg, getType(kw->value)));
kw_types.push_back(std::make_pair(kw->arg, getType(kw->value)));
}
CompilerType* starargs = node->starargs ? getType(node->starargs) : NULL;
......@@ -393,7 +393,7 @@ private:
void* visit_name(AST_Name* node) override {
if (scope_info->refersToGlobal(node->id)) {
if (node->id == "xrange") {
if (node->id.str() == "xrange") {
// printf("TODO guard here and return the classobj\n");
// return typeOfClassobj(xrange_cls);
}
......@@ -543,11 +543,11 @@ private:
// not part of the visitor api:
void _visit_alias(AST_alias* node) {
const std::string* name = &node->name;
if (node->asname.size())
name = &node->asname;
InternedString name = node->name;
if (node->asname.str().size())
name = node->asname;
_doSet(*name, UNKNOWN);
_doSet(name, UNKNOWN);
}
void visit_import(AST_Import* node) override {
......@@ -616,11 +616,11 @@ private:
speculation(speculation) {}
public:
ConcreteCompilerType* getTypeAtBlockEnd(const std::string& name, CFGBlock* block) override {
ConcreteCompilerType* getTypeAtBlockEnd(InternedString name, CFGBlock* block) override {
assert(block->successors.size() > 0);
return getTypeAtBlockStart(name, block->successors[0]);
}
ConcreteCompilerType* getTypeAtBlockStart(const std::string& name, CFGBlock* block) override {
ConcreteCompilerType* getTypeAtBlockStart(InternedString name, CFGBlock* block) override {
CompilerType* base = starting_types[block][name];
ASSERT(base != NULL, "%s %d", name.c_str(), block->idx);
......@@ -692,13 +692,13 @@ public:
initial_types[arg_name->id] = unboxedType(arg_types[i]);
}
if (arg_names.vararg->size()) {
initial_types[*arg_names.vararg] = unboxedType(arg_types[i]);
if (arg_names.vararg.str().size()) {
initial_types[arg_names.vararg] = unboxedType(arg_types[i]);
i++;
}
if (arg_names.kwarg->size()) {
initial_types[*arg_names.kwarg] = unboxedType(arg_types[i]);
if (arg_names.kwarg.str().size()) {
initial_types[arg_names.kwarg] = unboxedType(arg_types[i]);
i++;
}
......
......@@ -18,6 +18,7 @@
#include <unordered_map>
#include <vector>
#include "core/stringpool.h"
#include "core/types.h"
namespace pyston {
......@@ -36,12 +37,11 @@ public:
virtual ~TypeAnalysis() {}
virtual ConcreteCompilerType* getTypeAtBlockStart(const std::string& name, CFGBlock* block) = 0;
virtual ConcreteCompilerType* getTypeAtBlockEnd(const std::string& name, CFGBlock* block) = 0;
virtual ConcreteCompilerType* getTypeAtBlockStart(InternedString name, CFGBlock* block) = 0;
virtual ConcreteCompilerType* getTypeAtBlockEnd(InternedString name, CFGBlock* block) = 0;
virtual BoxedClass* speculatedExprClass(AST_expr*) = 0;
};
// TypeAnalysis* analyze(CFG *cfg, std::unordered_map<std::string, ConcreteCompilerType*> arg_types);
TypeAnalysis* doTypeAnalysis(CFG* cfg, const SourceInfo::ArgNames& arg_names,
const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel::EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info);
......
......@@ -59,7 +59,7 @@ union Value {
class ASTInterpreter {
public:
typedef llvm::StringMap<Box*> SymMap;
typedef std::unordered_map<InternedString, Box*> SymMap;
ASTInterpreter(CompiledFunction* compiled_function);
......@@ -71,7 +71,7 @@ private:
Box* createFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body);
Value doBinOp(Box* left, Box* right, int op, BinExpType exp_type);
void doStore(AST_expr* node, Value value);
void doStore(const std::string& name, Value value);
void doStore(InternedString name, Value value);
void eraseDeadSymbols();
Value visit_assert(AST_Assert* node);
......@@ -138,7 +138,7 @@ public:
CompiledFunction* getCF() { return compiled_func; }
FrameInfo* getFrameInfo() { return &frame_info; }
const SymMap& getSymbolTable() { return sym_table; }
void addSymbol(const std::string& name, Box* value, bool allow_duplicates);
void addSymbol(InternedString name, Box* value, bool allow_duplicates);
void gcVisit(GCVisitor* visitor);
};
......@@ -170,7 +170,7 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
return v.o ? v.o : None;
}
void ASTInterpreter::addSymbol(const std::string& name, Box* value, bool allow_duplicates) {
void ASTInterpreter::addSymbol(InternedString name, Box* value, bool allow_duplicates) {
if (!allow_duplicates)
assert(sym_table.count(name) == 0);
sym_table[name] = value;
......@@ -188,7 +188,9 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
for (const auto& p : locals->d) {
assert(p.first->cls == str_cls);
interpreter.addSymbol(static_cast<BoxedString*>(p.first)->s, p.second, false);
auto name = static_cast<BoxedString*>(p.first)->s;
InternedString interned = cf->clfunc->source->getInternedStrings().get(name);
interpreter.addSymbol(interned, p.second, false);
}
CFGBlock* start_block = NULL;
......@@ -200,7 +202,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
assert(asgn->targets.size() == 1);
assert(asgn->targets[0]->type == AST_TYPE::Name);
auto name = ast_cast<AST_Name>(asgn->targets[0]);
assert(name->id[0] == '#');
assert(name->id.str()[0] == '#');
interpreter.addSymbol(name->id, expr_val, true);
break;
} else if (enclosing_stmt->type == AST_TYPE::Expr) {
......@@ -267,10 +269,10 @@ BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
assert(interpreter);
BoxedDict* rtn = new BoxedDict();
for (auto&& l : interpreter->getSymbolTable()) {
if (only_user_visible && (l.getKey()[0] == '!' || l.getKey()[0] == '#'))
if (only_user_visible && (l.first.str()[0] == '!' || l.first.str()[0] == '#'))
continue;
rtn->d[new BoxedString(l.getKey())] = l.getValue();
rtn->d[new BoxedString(l.first.str())] = l.second;
}
return rtn;
}
......@@ -296,9 +298,9 @@ void gatherInterpreterRoots(GCVisitor* visitor) {
ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
: compiled_func(compiled_function), source_info(compiled_function->clfunc->source), scope_info(0), next_block(0),
current_block(0), current_inst(0), last_exception(NULL, NULL, NULL), passed_closure(0), created_closure(0),
generator(0), edgecount(0), frame_info(ExcInfo(NULL, NULL, NULL)) {
: compiled_func(compiled_function), source_info(compiled_function->clfunc->source), scope_info(0), current_block(0),
current_inst(0), last_exception(NULL, NULL, NULL), passed_closure(0), created_closure(0), generator(0),
edgecount(0), frame_info(ExcInfo(NULL, NULL, NULL)) {
CLFunction* f = compiled_function->clfunc;
if (!source_info->cfg)
......@@ -328,12 +330,12 @@ void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGener
}
}
if (source_info->arg_names.vararg && !source_info->arg_names.vararg->empty()) {
doStore(*source_info->arg_names.vararg, argsArray[i++]);
if (source_info->arg_names.vararg.str().size()) {
doStore(source_info->arg_names.vararg, argsArray[i++]);
}
if (source_info->arg_names.kwarg && !source_info->arg_names.kwarg->empty()) {
doStore(*source_info->arg_names.kwarg, argsArray[i++]);
if (source_info->arg_names.kwarg.str().size()) {
doStore(source_info->arg_names.kwarg, argsArray[i++]);
}
}
......@@ -400,12 +402,12 @@ void ASTInterpreter::eraseDeadSymbols() {
source_info->phis
= computeRequiredPhis(source_info->arg_names, source_info->cfg, source_info->liveness, scope_info);
std::vector<std::string> dead_symbols;
std::vector<InternedString> dead_symbols;
for (auto&& it : sym_table) {
if (!source_info->liveness->isLiveAtEnd(it.getKey(), current_block)) {
dead_symbols.push_back(it.getKey());
} else if (source_info->phis->isRequiredAfter(it.getKey(), current_block)) {
assert(!scope_info->refersToGlobal(it.getKey()));
if (!source_info->liveness->isLiveAtEnd(it.first, current_block)) {
dead_symbols.push_back(it.first);
} else if (source_info->phis->isRequiredAfter(it.first, current_block)) {
assert(!scope_info->refersToGlobal(it.first));
} else {
}
}
......@@ -430,7 +432,7 @@ Value ASTInterpreter::doBinOp(Box* left, Box* right, int op, BinExpType exp_type
return Value();
}
void ASTInterpreter::doStore(const std::string& name, Value value) {
void ASTInterpreter::doStore(InternedString name, Value value) {
if (scope_info->refersToGlobal(name)) {
setattr(source_info->parent_module, name.c_str(), value.o);
} else {
......@@ -523,7 +525,7 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
found_entry = p.first;
}
std::map<std::string, Box*> sorted_symbol_table;
std::map<InternedString, Box*> sorted_symbol_table;
auto phis = compiled_func->clfunc->source->phis;
for (auto& name : phis->definedness.getDefinedNamesAtEnd(current_block)) {
......@@ -533,37 +535,38 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
if (phis->isPotentiallyUndefinedAfter(name, current_block)) {
bool is_defined = it != sym_table.end();
sorted_symbol_table[getIsDefinedName(name)] = (Box*)is_defined;
// TODO only mangle once
sorted_symbol_table[getIsDefinedName(name, source_info->getInternedStrings())] = (Box*)is_defined;
if (is_defined)
assert(it->getValue() != NULL);
sorted_symbol_table[name] = is_defined ? it->getValue() : NULL;
assert(it->second != NULL);
sorted_symbol_table[name] = is_defined ? it->second : NULL;
} else {
ASSERT(it != sym_table.end(), "%s", name.c_str());
sorted_symbol_table[it->getKey()] = it->getValue();
sorted_symbol_table[it->first] = it->second;
}
}
if (generator)
sorted_symbol_table[PASSED_GENERATOR_NAME] = generator;
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_GENERATOR_NAME)] = generator;
if (passed_closure)
sorted_symbol_table[PASSED_CLOSURE_NAME] = passed_closure;
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_CLOSURE_NAME)] = passed_closure;
if (created_closure)
sorted_symbol_table[CREATED_CLOSURE_NAME] = created_closure;
sorted_symbol_table[source_info->getInternedStrings().get(CREATED_CLOSURE_NAME)] = created_closure;
if (found_entry == nullptr) {
OSREntryDescriptor* entry = OSREntryDescriptor::create(compiled_func, node);
for (auto& it : sorted_symbol_table) {
if (isIsDefinedName(it.first))
if (isIsDefinedName(it.first.str()))
entry->args[it.first] = BOOL;
else if (it.first == PASSED_GENERATOR_NAME)
else if (it.first.str() == PASSED_GENERATOR_NAME)
entry->args[it.first] = GENERATOR;
else if (it.first == PASSED_CLOSURE_NAME || it.first == CREATED_CLOSURE_NAME)
else if (it.first.str() == PASSED_CLOSURE_NAME || it.first.str() == CREATED_CLOSURE_NAME)
entry->args[it.first] = CLOSURE;
else {
assert(it.first[0] != '!');
assert(it.first.str()[0] != '!');
entry->args[it.first] = UNKNOWN;
}
}
......@@ -669,8 +672,8 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
assert(node->args.size() == 0);
BoxedDict* dict = new BoxedDict;
for (auto& p : sym_table) {
llvm::StringRef s = p.first();
if (s[0] == '!' || s[0] == '#')
auto s = p.first;
if (s.str()[0] == '!' || s.str()[0] == '#')
continue;
dict->d[new BoxedString(s.str())] = p.second;
......@@ -835,7 +838,7 @@ Value ASTInterpreter::visit_classDef(AST_ClassDef* node) {
CLFunction* cl = wrapFunction(node, nullptr, node->body, source_info);
Box* attrDict = runtimeCall(boxCLFunction(cl, closure, false, {}), ArgPassSpec(0), 0, 0, 0, 0, 0);
Box* classobj = createUserClass(&node->name, basesTuple, attrDict);
Box* classobj = createUserClass(&node->name.str(), basesTuple, attrDict);
for (int i = decorators.size() - 1; i >= 0; i--)
classobj = runtimeCall(decorators[i], ArgPassSpec(1), classobj, 0, 0, 0, 0);
......@@ -868,7 +871,7 @@ Value ASTInterpreter::visit_assert(AST_Assert* node) {
}
Value ASTInterpreter::visit_global(AST_Global* node) {
for (std::string& name : node->names)
for (auto name : node->names)
sym_table.erase(name);
return Value();
}
......@@ -892,7 +895,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
AST_Name* target = (AST_Name*)target_;
if (scope_info->refersToGlobal(target->id)) {
// Can't use delattr since the errors are different:
delGlobal(source_info->parent_module, &target->id);
delGlobal(source_info->parent_module, &target->id.str());
continue;
}
......@@ -1015,7 +1018,7 @@ Value ASTInterpreter::visit_call(AST_Call* node) {
Value v;
Value func;
std::string* attr = nullptr;
InternedString attr;
bool is_callattr = false;
bool callattr_clsonly = false;
......@@ -1024,15 +1027,16 @@ Value ASTInterpreter::visit_call(AST_Call* node) {
callattr_clsonly = false;
AST_Attribute* attr_ast = ast_cast<AST_Attribute>(node->func);
func = visit_expr(attr_ast->value);
attr = &attr_ast->attr;
attr = attr_ast->attr;
} else if (node->func->type == AST_TYPE::ClsAttribute) {
is_callattr = true;
callattr_clsonly = true;
AST_ClsAttribute* attr_ast = ast_cast<AST_ClsAttribute>(node->func);
func = visit_expr(attr_ast->value);
attr = &attr_ast->attr;
} else
attr = attr_ast->attr;
} else {
func = visit_expr(node->func);
}
std::vector<Box*> args;
for (AST_expr* e : node->args)
......@@ -1040,7 +1044,7 @@ Value ASTInterpreter::visit_call(AST_Call* node) {
std::vector<const std::string*> keywords;
for (AST_keyword* k : node->keywords) {
keywords.push_back(&k->arg);
keywords.push_back(&k->arg.str());
args.push_back(visit_expr(k->value).o);
}
......@@ -1053,9 +1057,10 @@ Value ASTInterpreter::visit_call(AST_Call* node) {
ArgPassSpec argspec(node->args.size(), node->keywords.size(), node->starargs, node->kwargs);
if (is_callattr) {
return callattr(func.o, attr, CallattrFlags({.cls_only = callattr_clsonly, .null_on_nonexistent = false }),
argspec, args.size() > 0 ? args[0] : 0, args.size() > 1 ? args[1] : 0,
args.size() > 2 ? args[2] : 0, args.size() > 3 ? &args[3] : 0, &keywords);
return callattr(func.o, &attr.str(),
CallattrFlags({.cls_only = callattr_clsonly, .null_on_nonexistent = false }), argspec,
args.size() > 0 ? args[0] : 0, args.size() > 1 ? args[1] : 0, args.size() > 2 ? args[2] : 0,
args.size() > 3 ? &args[3] : 0, &keywords);
} else {
return runtimeCall(func.o, argspec, args.size() > 0 ? args[0] : 0, args.size() > 1 ? args[1] : 0,
args.size() > 2 ? args[2] : 0, args.size() > 3 ? &args[3] : 0, &keywords);
......@@ -1122,7 +1127,7 @@ Value ASTInterpreter::visit_str(AST_Str* node) {
Value ASTInterpreter::visit_name(AST_Name* node) {
if (scope_info->refersToGlobal(node->id))
return getGlobal(source_info->parent_module, &node->id);
return getGlobal(source_info->parent_module, &node->id.str());
else if (scope_info->refersToClosure(node->id)) {
return getattr(passed_closure, node->id.c_str());
} else {
......@@ -1134,7 +1139,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
// classdefs have different scoping rules than functions:
if (source_info->ast->type == AST_TYPE::ClassDef)
return getGlobal(source_info->parent_module, &node->id);
return getGlobal(source_info->parent_module, &node->id.str());
assertNameDefined(0, node->id.c_str(), UnboundLocalError, true);
return Value();
......
......@@ -34,7 +34,8 @@ namespace pyston {
DS_DEFINE_RWLOCK(codegen_rwlock);
SourceInfo::SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, AST* ast, const std::vector<AST_stmt*>& body)
: parent_module(m), scoping(scoping), ast(ast), cfg(NULL), liveness(NULL), phis(NULL), arg_names(ast), body(body) {
: parent_module(m), scoping(scoping), ast(ast), cfg(NULL), liveness(NULL), phis(NULL), arg_names(ast, scoping),
body(body) {
switch (ast->type) {
case AST_TYPE::ClassDef:
case AST_TYPE::Lambda:
......
......@@ -272,14 +272,14 @@ computeBlockTraversalOrder(const BlockSet& full_blocks, const BlockSet& partial_
return rtn;
}
static ConcreteCompilerType* getTypeAtBlockStart(TypeAnalysis* types, const std::string& name, CFGBlock* block) {
if (isIsDefinedName(name))
static ConcreteCompilerType* getTypeAtBlockStart(TypeAnalysis* types, InternedString name, CFGBlock* block) {
if (isIsDefinedName(name.str()))
return BOOL;
else if (name == PASSED_GENERATOR_NAME)
else if (name.str() == PASSED_GENERATOR_NAME)
return GENERATOR;
else if (name == PASSED_CLOSURE_NAME)
else if (name.str() == PASSED_CLOSURE_NAME)
return CLOSURE;
else if (name == CREATED_CLOSURE_NAME)
else if (name.str() == CREATED_CLOSURE_NAME)
return CLOSURE;
else
return types->getTypeAtBlockStart(name, block);
......@@ -450,9 +450,10 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
}
ASSERT(speculated_class, "%s", phi_type->debugName().c_str());
assert(p.first[0] != '!');
assert(p.first.str()[0] != '!');
std::string is_defined_name = getIsDefinedName(p.first);
// TODO cache this
InternedString is_defined_name = getIsDefinedName(p.first, source->getInternedStrings());
llvm::Value* prev_guard_val = NULL;
ConcreteCompilerVariable* is_defined_var = NULL;
......@@ -507,7 +508,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
}
if (VERBOSITY("irgen"))
v->setName("prev_" + p.first);
v->setName("prev_" + p.first.str());
(*osr_syms)[p.first] = new ConcreteCompilerVariable(phi_type, v, true);
}
......@@ -543,7 +544,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
std::unordered_map<CFGBlock*, SymbolTable*> ending_symbol_tables;
std::unordered_map<CFGBlock*, ConcreteSymbolTable*> phi_ending_symbol_tables;
typedef std::unordered_map<std::string, std::pair<ConcreteCompilerType*, llvm::PHINode*>> PHITable;
typedef std::unordered_map<InternedString, std::pair<ConcreteCompilerType*, llvm::PHINode*>> PHITable;
std::unordered_map<CFGBlock*, PHITable*> created_phis;
CFGBlock* initial_block = NULL;
......@@ -680,7 +681,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
// analyzed_type->debugName().c_str());
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(analyzed_type->llvmType(),
block->predecessors.size() + 1, p.first);
block->predecessors.size() + 1, p.first.str());
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(analyzed_type, phi, true);
generator->giveLocalSymbol(p.first, var);
(*phis)[p.first] = std::make_pair(analyzed_type, phi);
......@@ -696,27 +697,28 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
}
std::unordered_set<std::string> names;
std::unordered_set<InternedString> names;
for (const auto& s : source->phis->getAllRequiredFor(block)) {
names.insert(s);
if (source->phis->isPotentiallyUndefinedAfter(s, block->predecessors[0])) {
names.insert(getIsDefinedName(s));
names.insert(getIsDefinedName(s, source->getInternedStrings()));
}
}
if (source->getScopeInfo()->createsClosure())
names.insert(CREATED_CLOSURE_NAME);
names.insert(source->getInternedStrings().get(CREATED_CLOSURE_NAME));
if (source->getScopeInfo()->takesClosure())
names.insert(PASSED_CLOSURE_NAME);
names.insert(source->getInternedStrings().get(PASSED_CLOSURE_NAME));
if (source->is_generator)
names.insert(PASSED_GENERATOR_NAME);
names.insert(source->getInternedStrings().get(PASSED_GENERATOR_NAME));
for (const auto& s : names) {
// printf("adding guessed phi for %s\n", s.c_str());
ConcreteCompilerType* type = getTypeAtBlockStart(types, s, block);
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(type->llvmType(), block->predecessors.size(), s);
llvm::PHINode* phi
= emitter->getBuilder()->CreatePHI(type->llvmType(), block->predecessors.size(), s.str());
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(type, phi, true);
generator->giveLocalSymbol(s, var);
......@@ -776,7 +778,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
for (ConcreteSymbolTable::iterator it = pred_st->begin(); it != pred_st->end(); it++) {
// printf("adding phi for %s\n", it->first.c_str());
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(it->second->getType()->llvmType(),
block->predecessors.size(), it->first);
block->predecessors.size(), it->first.str());
// emitter->getBuilder()->CreateCall(g.funcs.dump, phi);
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(it->second->getType(), phi, true);
generator->giveLocalSymbol(it->first, var);
......@@ -882,7 +884,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
llvm_phi->addIncoming(v->getValue(), osr_unbox_block_end);
}
std::string is_defined_name = getIsDefinedName(it->first);
InternedString is_defined_name = getIsDefinedName(it->first, source->getInternedStrings());
for (int i = 0; i < block_guards.size(); i++) {
GuardList::BlockEntryGuard* guard = block_guards[i];
......
......@@ -91,7 +91,7 @@ extern const std::string CREATED_CLOSURE_NAME;
extern const std::string PASSED_CLOSURE_NAME;
extern const std::string PASSED_GENERATOR_NAME;
std::string getIsDefinedName(const std::string& name);
InternedString getIsDefinedName(InternedString name, InternedStringPool& interned_strings);
bool isIsDefinedName(const std::string& name);
CompiledFunction* doCompile(SourceInfo* source, const OSREntryDescriptor* entry_descriptor,
......
......@@ -69,7 +69,7 @@ void raiseFutureImportErrorNotBeginning(const char* file, AST* node) {
class BadFutureImportVisitor : public NoopASTVisitor {
public:
virtual bool visit_importfrom(AST_ImportFrom* node) {
if (node->module == "__future__") {
if (node->module.str() == "__future__") {
raiseFutureImportErrorNotBeginning(file, node);
}
return true;
......@@ -103,14 +103,14 @@ FutureFlags getFutureFlags(AST_Module* m, const char* file) {
for (int i = 0; i < m->body.size(); i++) {
AST_stmt* stmt = m->body[i];
if (stmt->type == AST_TYPE::ImportFrom && static_cast<AST_ImportFrom*>(stmt)->module == "__future__") {
if (stmt->type == AST_TYPE::ImportFrom && static_cast<AST_ImportFrom*>(stmt)->module.str() == "__future__") {
if (future_import_allowed) {
// We have a `from __future__` import statement, and we are
// still at the top of the file, so just set the appropriate
// future flag for each imported option.
for (AST_alias* alias : static_cast<AST_ImportFrom*>(stmt)->names) {
const std::string& option_name = alias->name;
const std::string& option_name = alias->name.str();
auto iter = future_options.find(option_name);
if (iter == future_options.end()) {
// If it's not one of the available options, throw an error.
......
......@@ -42,39 +42,44 @@
namespace pyston {
// TODO terrible place for these!
SourceInfo::ArgNames::ArgNames(AST* ast) {
SourceInfo::ArgNames::ArgNames(AST* ast, ScopingAnalysis* scoping) {
if (ast->type == AST_TYPE::Module || ast->type == AST_TYPE::ClassDef) {
args = NULL;
kwarg = vararg = NULL;
kwarg = vararg = scoping->getInternedStrings().get("");
} else if (ast->type == AST_TYPE::FunctionDef) {
AST_FunctionDef* f = ast_cast<AST_FunctionDef>(ast);
args = &f->args->args;
vararg = &f->args->vararg;
kwarg = &f->args->kwarg;
vararg = f->args->vararg;
kwarg = f->args->kwarg;
} else if (ast->type == AST_TYPE::Lambda) {
AST_Lambda* l = ast_cast<AST_Lambda>(ast);
args = &l->args->args;
vararg = &l->args->vararg;
kwarg = &l->args->kwarg;
vararg = l->args->vararg;
kwarg = l->args->kwarg;
} else {
RELEASE_ASSERT(0, "%d", ast->type);
}
}
std::string SourceInfo::mangleName(const std::string& id) {
InternedString SourceInfo::mangleName(InternedString id) {
// TODO should cache the results of this
assert(ast);
if (ast->type == AST_TYPE::Module)
return id;
return getScopeInfo()->mangleName(id);
}
InternedStringPool& SourceInfo::getInternedStrings() {
return scoping->getInternedStrings();
}
const std::string SourceInfo::getName() {
assert(ast);
switch (ast->type) {
case AST_TYPE::ClassDef:
return ast_cast<AST_ClassDef>(ast)->name;
return ast_cast<AST_ClassDef>(ast)->name.str();
case AST_TYPE::FunctionDef:
return ast_cast<AST_FunctionDef>(ast)->name;
return ast_cast<AST_FunctionDef>(ast)->name.str();
case AST_TYPE::Lambda:
return "<lambda>";
case AST_TYPE::Module:
......
......@@ -289,14 +289,15 @@ const std::string CREATED_CLOSURE_NAME = "!created_closure";
const std::string PASSED_CLOSURE_NAME = "!passed_closure";
const std::string PASSED_GENERATOR_NAME = "!passed_generator";
std::string getIsDefinedName(const std::string& name) {
return "!is_defined_" + name;
}
bool isIsDefinedName(const std::string& name) {
return startswith(name, "!is_defined_");
}
InternedString getIsDefinedName(InternedString name, InternedStringPool& interned_strings) {
// TODO could cache this
return interned_strings.get("!is_defined_" + name.str());
}
class IRGeneratorImpl : public IRGenerator {
private:
IRGenState* irstate;
......@@ -376,12 +377,20 @@ private:
emitter.getBuilder()->SetInsertPoint(curblock);
}
template <typename T> InternedString internString(T&& s) {
return irstate->getSourceInfo()->getInternedStrings().get(std::forward<T>(s));
}
InternedString getIsDefinedName(InternedString name) {
return pyston::getIsDefinedName(name, irstate->getSourceInfo()->getInternedStrings());
}
CompilerVariable* evalAttribute(AST_Attribute* node, UnwindInfo unw_info) {
assert(state != PARTIAL);
CompilerVariable* value = evalExpr(node->value, unw_info);
CompilerVariable* rtn = value->getattr(emitter, getOpInfoForNode(node, unw_info), &node->attr, false);
CompilerVariable* rtn = value->getattr(emitter, getOpInfoForNode(node, unw_info), &node->attr.str(), false);
value->decvref(emitter);
return rtn;
}
......@@ -390,7 +399,7 @@ private:
assert(state != PARTIAL);
CompilerVariable* value = evalExpr(node->value, unw_info);
CompilerVariable* rtn = value->getattr(emitter, getOpInfoForNode(node, unw_info), &node->attr, true);
CompilerVariable* rtn = value->getattr(emitter, getOpInfoForNode(node, unw_info), &node->attr.str(), true);
value->decvref(emitter);
return rtn;
}
......@@ -466,7 +475,7 @@ private:
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(DICT, v, true);
for (auto& p : symbol_table) {
if (p.first[0] == '!' || p.first[0] == '#')
if (p.first.str()[0] == '!' || p.first.str()[0] == '#')
continue;
ConcreteCompilerVariable* is_defined_var
......@@ -479,7 +488,7 @@ private:
// TODO super dumb that it reallocates the name again
CompilerVariable* _r
= rtn->callattr(emitter, getEmptyOpInfo(unw_info), &setitem_str, true, ArgPassSpec(2),
{ makeStr(new std::string(p.first)), converted }, NULL);
{ makeStr(new std::string(p.first.str())), converted }, NULL);
converted->decvref(emitter);
_r->decvref(emitter);
} else {
......@@ -496,7 +505,7 @@ private:
// TODO super dumb that it reallocates the name again
CompilerVariable* _r
= rtn->callattr(emitter, getEmptyOpInfo(unw_info), &setitem_str, true, ArgPassSpec(2),
{ makeStr(new std::string(p.first)), converted }, NULL);
{ makeStr(new std::string(p.first.str())), converted }, NULL);
converted->decvref(emitter);
_r->decvref(emitter);
emitter.getBuilder()->CreateBr(join);
......@@ -698,20 +707,20 @@ private:
bool is_callattr;
bool callattr_clsonly = false;
std::string* attr = NULL;
const std::string* attr = NULL;
CompilerVariable* func;
if (node->func->type == AST_TYPE::Attribute) {
is_callattr = true;
callattr_clsonly = false;
AST_Attribute* attr_ast = ast_cast<AST_Attribute>(node->func);
func = evalExpr(attr_ast->value, unw_info);
attr = &attr_ast->attr;
attr = &attr_ast->attr.str();
} else if (node->func->type == AST_TYPE::ClsAttribute) {
is_callattr = true;
callattr_clsonly = true;
AST_ClsAttribute* attr_ast = ast_cast<AST_ClsAttribute>(node->func);
func = evalExpr(attr_ast->value, unw_info);
attr = &attr_ast->attr;
attr = &attr_ast->attr.str();
} else {
is_callattr = false;
func = evalExpr(node->func, unw_info);
......@@ -727,7 +736,7 @@ private:
// keyword names already populated:
if (!keyword_names->size()) {
for (auto kw : node->keywords) {
keyword_names->push_back(&kw->arg);
keyword_names->push_back(&kw->arg.str());
}
}
} else {
......@@ -871,7 +880,7 @@ private:
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr));
llvm_args.push_back(embedConstantPtr(&node->id, g.llvm_str_type_ptr));
llvm_args.push_back(embedConstantPtr(&node->id.str(), g.llvm_str_type_ptr));
llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::getGlobal, llvm_args, unw_info);
llvm::Value* r = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
......@@ -880,7 +889,7 @@ private:
llvm::Value* r
= emitter.createCall2(unw_info, g.funcs.getGlobal,
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr),
embedConstantPtr(&node->id, g.llvm_str_type_ptr));
embedConstantPtr(&node->id.str(), g.llvm_str_type_ptr));
return new ConcreteCompilerVariable(UNKNOWN, r, true);
}
}
......@@ -891,7 +900,7 @@ private:
auto scope_info = irstate->getScopeInfo();
bool is_kill = irstate->getSourceInfo()->liveness->isKill(node, myblock);
assert(!is_kill || node->id[0] == '#');
assert(!is_kill || node->id.str()[0] == '#');
if (scope_info->refersToGlobal(node->id)) {
assert(!is_kill);
......@@ -900,10 +909,10 @@ private:
assert(!is_kill);
assert(scope_info->takesClosure());
CompilerVariable* closure = _getFake(PASSED_CLOSURE_NAME, false);
CompilerVariable* closure = _getFake(internString(PASSED_CLOSURE_NAME), false);
assert(closure);
return closure->getattr(emitter, getEmptyOpInfo(unw_info), &node->id, false);
return closure->getattr(emitter, getEmptyOpInfo(unw_info), &node->id.str(), false);
} else {
if (symbol_table.find(node->id) == symbol_table.end()) {
// classdefs have different scoping rules than functions:
......@@ -915,13 +924,13 @@ private:
// state = DEAD;
llvm::CallSite call = emitter.createCall(
unw_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(node->id + '\0'),
{ getConstantInt(0, g.i1), getStringConstantPtr(node->id.str() + '\0'),
embedConstantPtr(UnboundLocalError, g.llvm_class_type_ptr), getConstantInt(true, g.i1) });
call.setDoesNotReturn();
return undefVariable();
}
std::string defined_name = getIsDefinedName(node->id);
InternedString defined_name = getIsDefinedName(node->id);
ConcreteCompilerVariable* is_defined_var
= static_cast<ConcreteCompilerVariable*>(_getFake(defined_name, true));
......@@ -940,7 +949,7 @@ private:
}
emitter.createCall(unw_info, g.funcs.assertNameDefined,
{ i1FromBool(emitter, is_defined_var), getStringConstantPtr(node->id + '\0'),
{ i1FromBool(emitter, is_defined_var), getStringConstantPtr(node->id.str() + '\0'),
embedConstantPtr(UnboundLocalError, g.llvm_class_type_ptr),
getConstantInt(true, g.i1) });
......@@ -1106,7 +1115,7 @@ private:
CompilerVariable* evalYield(AST_Yield* node, UnwindInfo unw_info) {
assert(state != PARTIAL);
CompilerVariable* generator = _getFake(PASSED_GENERATOR_NAME, false);
CompilerVariable* generator = _getFake(internString(PASSED_GENERATOR_NAME), false);
ConcreteCompilerVariable* convertedGenerator = generator->makeConverted(emitter, generator->getBoxType());
......@@ -1304,7 +1313,7 @@ private:
joined_st[p.first] = new ConcreteCompilerVariable(merged_type, converted1->getValue(), true);
} else {
emitter.getBuilder()->SetInsertPoint(join_block);
llvm::PHINode* phi = emitter.getBuilder()->CreatePHI(merged_type->llvmType(), 2, p.first);
llvm::PHINode* phi = emitter.getBuilder()->CreatePHI(merged_type->llvmType(), 2, p.first.str());
phi->addIncoming(converted1->getValue(), ramp_block);
phi->addIncoming(converted2->getValue(), curblock);
joined_st[p.first] = new ConcreteCompilerVariable(merged_type, phi, true);
......@@ -1353,15 +1362,15 @@ private:
return rtn;
}
void _setFake(std::string name, CompilerVariable* val) {
assert(name[0] == '!');
void _setFake(InternedString name, CompilerVariable* val) {
assert(name.str()[0] == '!');
CompilerVariable*& cur = symbol_table[name];
assert(cur == NULL);
cur = val;
}
CompilerVariable* _getFake(std::string name, bool allow_missing = false) {
assert(name[0] == '!');
CompilerVariable* _getFake(InternedString name, bool allow_missing = false) {
assert(name.str()[0] == '!');
auto it = symbol_table.find(name);
if (it == symbol_table.end()) {
assert(allow_missing);
......@@ -1370,7 +1379,7 @@ private:
return it->second;
}
CompilerVariable* _popFake(std::string name, bool allow_missing = false) {
CompilerVariable* _popFake(InternedString name, bool allow_missing = false) {
CompilerVariable* rtn = _getFake(name, allow_missing);
symbol_table.erase(name);
if (!allow_missing)
......@@ -1378,8 +1387,8 @@ private:
return rtn;
}
void _doSet(const std::string& name, CompilerVariable* val, UnwindInfo unw_info) {
assert(name != "None");
void _doSet(InternedString name, CompilerVariable* val, UnwindInfo unw_info) {
assert(name.str() != "None");
auto scope_info = irstate->getScopeInfo();
assert(!scope_info->refersToClosure(name));
......@@ -1390,7 +1399,7 @@ private:
// TODO do something special here so that it knows to only emit a monomorphic inline cache?
ConcreteCompilerVariable* module = new ConcreteCompilerVariable(
MODULE, embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_value_type_ptr), false);
module->setattr(emitter, getEmptyOpInfo(unw_info), &name, val);
module->setattr(emitter, getEmptyOpInfo(unw_info), &name.str(), val);
module->decvref(emitter);
} else {
CompilerVariable*& prev = symbol_table[name];
......@@ -1401,15 +1410,15 @@ private:
val->incvref();
// Clear out the is_defined name since it is now definitely defined:
assert(!isIsDefinedName(name));
std::string defined_name = getIsDefinedName(name);
assert(!isIsDefinedName(name.str()));
InternedString defined_name = getIsDefinedName(name);
_popFake(defined_name, true);
if (scope_info->saveInClosure(name)) {
CompilerVariable* closure = _getFake(CREATED_CLOSURE_NAME, false);
CompilerVariable* closure = _getFake(internString(CREATED_CLOSURE_NAME), false);
assert(closure);
closure->setattr(emitter, getEmptyOpInfo(unw_info), &name, val);
closure->setattr(emitter, getEmptyOpInfo(unw_info), &name.str(), val);
}
}
}
......@@ -1417,7 +1426,7 @@ private:
void _doSetattr(AST_Attribute* target, CompilerVariable* val, UnwindInfo unw_info) {
assert(state != PARTIAL);
CompilerVariable* t = evalExpr(target->value, unw_info);
t->setattr(emitter, getEmptyOpInfo(unw_info), &target->attr, val);
t->setattr(emitter, getEmptyOpInfo(unw_info), &target->attr.str(), val);
t->decvref(emitter);
}
......@@ -1464,7 +1473,7 @@ private:
#ifndef NDEBUG
for (auto e : target->elts) {
ASSERT(e->type == AST_TYPE::Name && ast_cast<AST_Name>(e)->id[0] == '#',
ASSERT(e->type == AST_TYPE::Name && ast_cast<AST_Name>(e)->id.str()[0] == '#',
"should only be unpacking tuples into cfg-generated names!");
}
#endif
......@@ -1563,7 +1572,7 @@ private:
// TODO duplication with _createFunction:
CompilerVariable* created_closure = NULL;
if (scope_info->takesClosure()) {
created_closure = _getFake(CREATED_CLOSURE_NAME, false);
created_closure = _getFake(internString(CREATED_CLOSURE_NAME), false);
assert(created_closure);
}
......@@ -1581,8 +1590,8 @@ private:
attr_dict->decvref(emitter);
llvm::Value* classobj
= emitter.createCall3(unw_info, g.funcs.createUserClass, embedConstantPtr(&node->name, g.llvm_str_type_ptr),
llvm::Value* classobj = emitter.createCall3(unw_info, g.funcs.createUserClass,
embedConstantPtr(&node->name.str(), g.llvm_str_type_ptr),
bases_tuple->getValue(), converted_attr_dict->getValue());
// Note: createuserClass is free to manufacture non-class objects
......@@ -1647,7 +1656,7 @@ private:
void _doDelAttr(AST_Attribute* node, UnwindInfo unw_info) {
CompilerVariable* value = evalExpr(node->value, unw_info);
value->delattr(emitter, getEmptyOpInfo(unw_info), &node->attr);
value->delattr(emitter, getEmptyOpInfo(unw_info), &node->attr.str());
}
void _doDelName(AST_Name* target, UnwindInfo unw_info) {
......@@ -1656,7 +1665,7 @@ private:
// Can't use delattr since the errors are different:
emitter.createCall2(unw_info, g.funcs.delGlobal,
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr),
embedConstantPtr(&target->id, g.llvm_str_type_ptr));
embedConstantPtr(&target->id.str(), g.llvm_str_type_ptr));
return;
}
......@@ -1668,20 +1677,20 @@ private:
bool local_error_msg = (irstate->getSourceInfo()->ast->type != AST_TYPE::ClassDef);
if (symbol_table.count(target->id) == 0) {
llvm::CallSite call = emitter.createCall(unw_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(target->id + '\0'),
embedConstantPtr(NameError, g.llvm_class_type_ptr),
getConstantInt(local_error_msg, g.i1) });
llvm::CallSite call = emitter.createCall(
unw_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(target->id.str() + '\0'),
embedConstantPtr(NameError, g.llvm_class_type_ptr), getConstantInt(local_error_msg, g.i1) });
call.setDoesNotReturn();
return;
}
std::string defined_name = getIsDefinedName(target->id);
InternedString defined_name = getIsDefinedName(target->id);
ConcreteCompilerVariable* is_defined_var = static_cast<ConcreteCompilerVariable*>(_getFake(defined_name, true));
if (is_defined_var) {
emitter.createCall(unw_info, g.funcs.assertNameDefined,
{ i1FromBool(emitter, is_defined_var), getStringConstantPtr(target->id + '\0'),
{ i1FromBool(emitter, is_defined_var), getStringConstantPtr(target->id.str() + '\0'),
embedConstantPtr(NameError, g.llvm_class_type_ptr),
getConstantInt(local_error_msg, g.i1) });
_popFake(defined_name);
......@@ -1720,10 +1729,10 @@ private:
if (takes_closure) {
if (irstate->getScopeInfo()->createsClosure()) {
created_closure = _getFake(CREATED_CLOSURE_NAME, false);
created_closure = _getFake(internString(CREATED_CLOSURE_NAME), false);
} else {
assert(irstate->getScopeInfo()->passesThroughClosure());
created_closure = _getFake(PASSED_CLOSURE_NAME, false);
created_closure = _getFake(internString(PASSED_CLOSURE_NAME), false);
}
assert(created_closure);
}
......@@ -2188,16 +2197,22 @@ private:
}
}
template <typename T>
void loadArgument(const T& name, ConcreteCompilerType* t, llvm::Value* v, UnwindInfo unw_info) {
void loadArgument(InternedString name, ConcreteCompilerType* t, llvm::Value* v, UnwindInfo unw_info) {
ConcreteCompilerVariable* var = unboxVar(t, v, false);
_doSet(name, var, unw_info);
var->decvref(emitter);
}
void loadArgument(AST_expr* name, ConcreteCompilerType* t, llvm::Value* v, UnwindInfo unw_info) {
ConcreteCompilerVariable* var = unboxVar(t, v, false);
_doSet(name, var, unw_info);
var->decvref(emitter);
}
bool allowableFakeEndingSymbol(const std::string& name) {
return isIsDefinedName(name) || name == PASSED_CLOSURE_NAME || name == CREATED_CLOSURE_NAME
|| name == PASSED_GENERATOR_NAME;
bool allowableFakeEndingSymbol(InternedString name) {
// TODO this would be a great place to be able to use interned versions of the static names...
return isIsDefinedName(name.str()) || name.str() == PASSED_CLOSURE_NAME || name.str() == CREATED_CLOSURE_NAME
|| name.str() == PASSED_GENERATOR_NAME;
}
void endBlock(State new_state) {
......@@ -2209,7 +2224,7 @@ private:
ScopeInfo* scope_info = irstate->getScopeInfo();
// Additional names to remove; remove them after iteration is done to new mess up the iterators
std::vector<std::string> also_remove;
std::vector<InternedString> also_remove;
for (SymbolTable::iterator it = symbol_table.begin(); it != symbol_table.end();) {
if (allowableFakeEndingSymbol(it->first)) {
++it;
......@@ -2263,7 +2278,7 @@ private:
assert(!scope_info->refersToGlobal(*it));
CompilerVariable*& cur = symbol_table[*it];
std::string defined_name = getIsDefinedName(*it);
InternedString defined_name = getIsDefinedName(*it);
if (cur != NULL) {
// printf("defined on this path; ");
......@@ -2313,7 +2328,7 @@ public:
CompilerVariable* v = p.second;
v->serializeToFrame(stackmap_args);
pp->addFrameVar(p.first, v->getType());
pp->addFrameVar(p.first.str(), v->getType());
}
}
......@@ -2362,14 +2377,14 @@ public:
assert(it->second->getVrefs() == 1);
// this conversion should have already happened... should refactor this.
ConcreteCompilerType* ending_type;
if (isIsDefinedName(it->first)) {
if (isIsDefinedName(it->first.str())) {
assert(it->second->getType() == BOOL);
ending_type = BOOL;
} else if (it->first == PASSED_CLOSURE_NAME) {
} else if (it->first.str() == PASSED_CLOSURE_NAME) {
ending_type = getPassedClosureType();
} else if (it->first == CREATED_CLOSURE_NAME) {
} else if (it->first.str() == CREATED_CLOSURE_NAME) {
ending_type = getCreatedClosureType();
} else if (it->first == PASSED_GENERATOR_NAME) {
} else if (it->first.str() == PASSED_GENERATOR_NAME) {
ending_type = GENERATOR;
} else {
ending_type = types->getTypeAtBlockEnd(it->first, myblock);
......@@ -2385,8 +2400,8 @@ public:
return EndingState(st, phi_st, curblock);
}
void giveLocalSymbol(const std::string& name, CompilerVariable* var) override {
assert(name != "None");
void giveLocalSymbol(InternedString name, CompilerVariable* var) override {
assert(name.str() != "None");
ASSERT(!irstate->getScopeInfo()->refersToGlobal(name), "%s", name.c_str());
assert(var->getType() != BOXED_INT);
assert(var->getType() != BOXED_FLOAT);
......@@ -2426,7 +2441,7 @@ public:
if (scope_info->takesClosure()) {
passed_closure = AI;
_setFake(PASSED_CLOSURE_NAME, new ConcreteCompilerVariable(getPassedClosureType(), AI, true));
_setFake(internString(PASSED_CLOSURE_NAME), new ConcreteCompilerVariable(getPassedClosureType(), AI, true));
++AI;
}
......@@ -2435,11 +2450,12 @@ public:
passed_closure = embedConstantPtr(nullptr, g.llvm_closure_type_ptr);
llvm::Value* new_closure = emitter.getBuilder()->CreateCall(g.funcs.createClosure, passed_closure);
_setFake(CREATED_CLOSURE_NAME, new ConcreteCompilerVariable(getCreatedClosureType(), new_closure, true));
_setFake(internString(CREATED_CLOSURE_NAME),
new ConcreteCompilerVariable(getCreatedClosureType(), new_closure, true));
}
if (irstate->getSourceInfo()->is_generator) {
_setFake(PASSED_GENERATOR_NAME, new ConcreteCompilerVariable(GENERATOR, AI, true));
_setFake(internString(PASSED_GENERATOR_NAME), new ConcreteCompilerVariable(GENERATOR, AI, true));
++AI;
}
......@@ -2477,13 +2493,13 @@ public:
loadArgument((*arg_names.args)[i], arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
}
if (arg_names.vararg->size()) {
loadArgument(*arg_names.vararg, arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
if (arg_names.vararg.str().size()) {
loadArgument(arg_names.vararg, arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
i++;
}
if (arg_names.kwarg->size()) {
loadArgument(*arg_names.kwarg, arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
if (arg_names.kwarg.str().size()) {
loadArgument(arg_names.kwarg, arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
i++;
}
......@@ -2518,7 +2534,8 @@ CLFunction* wrapFunction(AST* node, AST_arguments* args, const std::vector<AST_s
if (cl == NULL) {
SourceInfo* si = new SourceInfo(source->parent_module, source->scoping, node, body);
if (args)
cl = new CLFunction(args->args.size(), args->defaults.size(), args->vararg.size(), args->kwarg.size(), si);
cl = new CLFunction(args->args.size(), args->defaults.size(), args->vararg.str().size(),
args->kwarg.str().size(), si);
else
cl = new CLFunction(0, 0, 0, 0, si);
}
......
......@@ -20,6 +20,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/Instructions.h"
#include "core/stringpool.h"
#include "core/types.h"
namespace llvm {
......@@ -38,9 +39,9 @@ struct PatchpointInfo;
class ScopeInfo;
class TypeAnalysis;
typedef std::unordered_map<std::string, CompilerVariable*> SymbolTable;
typedef std::map<std::string, CompilerVariable*> SortedSymbolTable;
typedef std::unordered_map<std::string, ConcreteCompilerVariable*> ConcreteSymbolTable;
typedef std::unordered_map<InternedString, CompilerVariable*> SymbolTable;
typedef std::map<InternedString, CompilerVariable*> SortedSymbolTable;
typedef std::unordered_map<InternedString, ConcreteCompilerVariable*> ConcreteSymbolTable;
extern const std::string CREATED_CLOSURE_NAME;
extern const std::string PASSED_CLOSURE_NAME;
......@@ -197,7 +198,7 @@ public:
virtual void doFunctionEntry(const SourceInfo::ArgNames& arg_names,
const std::vector<ConcreteCompilerType*>& arg_types) = 0;
virtual void giveLocalSymbol(const std::string& name, CompilerVariable* var) = 0;
virtual void giveLocalSymbol(InternedString name, CompilerVariable* var) = 0;
virtual void copySymbolsFrom(SymbolTable* st) = 0;
virtual void run(const CFGBlock* block) = 0;
virtual EndingState getEndingSymbolTable() = 0;
......
......@@ -17,6 +17,8 @@
#include <vector>
#include "core/stringpool.h"
namespace llvm {
class Function;
}
......@@ -33,7 +35,7 @@ private:
public:
CompiledFunction* const cf;
AST_Jump* const backedge;
typedef std::map<std::string, ConcreteCompilerType*> ArgMap;
typedef std::map<InternedString, ConcreteCompilerType*> ArgMap;
ArgMap args;
static OSREntryDescriptor* create(CompiledFunction* from_cf, AST_Jump* backedge) {
......
......@@ -43,6 +43,8 @@ private:
int start, end;
FILE* fp;
InternedStringPool* intern_pool;
void ensure(int num) {
if (end - start < num) {
fill();
......@@ -59,7 +61,7 @@ public:
printf("filled, now at %d-%d\n", start, end);
}
BufferedReader(FILE* fp) : start(0), end(0), fp(fp) {}
BufferedReader(FILE* fp) : start(0), end(0), fp(fp), intern_pool(NULL) {}
int bytesBuffered() { return (end - start); }
......@@ -81,8 +83,18 @@ public:
raw = readULL();
return d;
}
std::unique_ptr<InternedStringPool> createInternedPool();
InternedString readAndInternString();
void readAndInternStringVector(std::vector<InternedString>& v);
};
std::unique_ptr<InternedStringPool> BufferedReader::createInternedPool() {
assert(this->intern_pool == NULL);
this->intern_pool = new InternedStringPool();
return std::unique_ptr<InternedStringPool>(this->intern_pool);
}
AST* readASTMisc(BufferedReader* reader);
AST_expr* readASTExpr(BufferedReader* reader);
AST_stmt* readASTStmt(BufferedReader* reader);
......@@ -96,6 +108,20 @@ static std::string readString(BufferedReader* reader) {
return std::string(chars.begin(), chars.end());
}
InternedString BufferedReader::readAndInternString() {
std::string str = readString(this);
return intern_pool->get(std::move(str));
}
void BufferedReader::readAndInternStringVector(std::vector<InternedString>& v) {
int num_elts = readShort();
if (VERBOSITY("parsing") >= 2)
printf("%d elts to read\n", num_elts);
for (int i = 0; i < num_elts; i++) {
v.push_back(readAndInternString());
}
}
static void readStringVector(std::vector<std::string>& vec, BufferedReader* reader) {
int num_elts = reader->readShort();
if (VERBOSITY("parsing") >= 2)
......@@ -142,8 +168,8 @@ static int readColOffset(BufferedReader* reader) {
}
AST_alias* read_alias(BufferedReader* reader) {
std::string asname = readString(reader);
std::string name = readString(reader);
InternedString asname = reader->readAndInternString();
InternedString name = reader->readAndInternString();
AST_alias* rtn = new AST_alias(name, asname);
rtn->col_offset = -1;
......@@ -155,14 +181,15 @@ AST_alias* read_alias(BufferedReader* reader) {
AST_arguments* read_arguments(BufferedReader* reader) {
if (VERBOSITY("parsing") >= 2)
printf("reading arguments\n");
AST_arguments* rtn = new AST_arguments();
readExprVector(rtn->args, reader);
rtn->col_offset = -1;
readExprVector(rtn->defaults, reader);
rtn->kwarg = readString(reader);
rtn->kwarg = reader->readAndInternString();
rtn->lineno = -1;
rtn->vararg = readString(reader);
rtn->vararg = reader->readAndInternString();
return rtn;
}
......@@ -200,7 +227,7 @@ AST_AugAssign* read_augassign(BufferedReader* reader) {
AST_Attribute* read_attribute(BufferedReader* reader) {
AST_Attribute* rtn = new AST_Attribute();
rtn->attr = readString(reader);
rtn->attr = reader->readAndInternString();
rtn->col_offset = readColOffset(reader);
rtn->ctx_type = (AST_TYPE::AST_TYPE)reader->readByte();
rtn->lineno = reader->readULL();
......@@ -293,7 +320,7 @@ AST_ClassDef* read_classdef(BufferedReader* reader) {
rtn->col_offset = readColOffset(reader);
readExprVector(rtn->decorator_list, reader);
rtn->lineno = reader->readULL();
rtn->name = readString(reader);
rtn->name = reader->readAndInternString();
return rtn;
}
......@@ -395,7 +422,7 @@ AST_FunctionDef* read_functiondef(BufferedReader* reader) {
rtn->col_offset = readColOffset(reader);
readExprVector(rtn->decorator_list, reader);
rtn->lineno = reader->readULL();
rtn->name = readString(reader);
rtn->name = reader->readAndInternString();
return rtn;
}
......@@ -414,7 +441,7 @@ AST_Global* read_global(BufferedReader* reader) {
rtn->col_offset = readColOffset(reader);
rtn->lineno = reader->readULL();
readStringVector(rtn->names, reader);
reader->readAndInternStringVector(rtn->names);
return rtn;
}
......@@ -455,7 +482,7 @@ AST_ImportFrom* read_importfrom(BufferedReader* reader) {
rtn->col_offset = readColOffset(reader);
rtn->level = reader->readULL();
rtn->lineno = reader->readULL();
rtn->module = readString(reader);
rtn->module = reader->readAndInternString();
readMiscVector(rtn->names, reader);
return rtn;
}
......@@ -473,7 +500,7 @@ AST_Index* read_index(BufferedReader* reader) {
AST_keyword* read_keyword(BufferedReader* reader) {
AST_keyword* rtn = new AST_keyword();
rtn->arg = readString(reader);
rtn->arg = reader->readAndInternString();
rtn->col_offset = -1;
rtn->lineno = -1;
rtn->value = readASTExpr(reader);
......@@ -513,7 +540,8 @@ AST_ListComp* read_listcomp(BufferedReader* reader) {
AST_Module* read_module(BufferedReader* reader) {
if (VERBOSITY("parsing") >= 2)
printf("reading module\n");
AST_Module* rtn = new AST_Module();
AST_Module* rtn = new AST_Module(reader->createInternedPool());
readStmtVector(rtn->body, reader);
rtn->col_offset = -1;
......@@ -524,7 +552,7 @@ AST_Module* read_module(BufferedReader* reader) {
AST_Name* read_name(BufferedReader* reader) {
auto col_offset = readColOffset(reader);
auto ctx_type = (AST_TYPE::AST_TYPE)reader->readByte();
auto id = readString(reader);
auto id = reader->readAndInternString();
auto lineno = reader->readULL();
return new AST_Name(std::move(id), ctx_type, lineno, col_offset);
......
......@@ -19,10 +19,13 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <pypa/ast/visitor.hh>
#include <pypa/parser/parser.hh>
#include <sys/stat.h>
#include "llvm/ADT/STLExtras.h"
#include "core/ast.h"
#include "core/options.h"
#include "core/stats.h"
......@@ -40,14 +43,15 @@ void location(AST* t, pypa::Ast& a) {
t->col_offset = a.column;
}
AST_expr* readItem(pypa::AstExpression& e);
AST_stmt* readItem(pypa::AstStatement& s);
AST_ExceptHandler* readItem(pypa::AstExcept&);
AST_ExceptHandler* readItem(pypa::AstExceptPtr);
AST_expr* readItem(pypa::AstExpression& e, InternedStringPool& interned_strings);
AST_stmt* readItem(pypa::AstStatement& s, InternedStringPool& interned_strings);
AST_ExceptHandler* readItem(pypa::AstExcept&, InternedStringPool& interned_strings);
AST_ExceptHandler* readItem(pypa::AstExceptPtr, InternedStringPool& interned_strings);
template <typename T> auto readItem(std::shared_ptr<T>& t) -> decltype(readItem(*t)) {
template <typename T>
auto readItem(std::shared_ptr<T>& t, InternedStringPool& interned_strings) -> decltype(readItem(*t, interned_strings)) {
if (t)
return readItem(*t);
return readItem(*t, interned_strings);
return nullptr;
}
......@@ -165,124 +169,128 @@ AST_TYPE::AST_TYPE readItem(pypa::AstCompareOpType type) {
abort();
}
std::string readName(pypa::AstExpression& e) {
InternedString readName(pypa::AstExpression& e, InternedStringPool& interned_strings) {
assert(e.type == pypa::AstType::Name);
return static_cast<pypa::AstName&>(e).id;
return interned_strings.get(static_cast<pypa::AstName&>(e).id);
}
std::string readName(pypa::AstExpr& n) {
InternedString readName(pypa::AstExpr& n, InternedStringPool& interned_strings) {
if (!n) {
return std::string();
return interned_strings.get(std::string());
}
return readName(*n);
return readName(*n, interned_strings);
}
AST_keyword* readItem(pypa::AstKeyword& k) {
AST_keyword* readItem(pypa::AstKeyword& k, InternedStringPool& interned_strings) {
AST_keyword* ptr = new AST_keyword();
location(ptr, k);
ptr->arg = readName(k.name);
ptr->value = readItem(k.value);
ptr->arg = readName(k.name, interned_strings);
ptr->value = readItem(k.value, interned_strings);
return ptr;
}
void readVector(std::vector<AST_keyword*>& t, pypa::AstExprList& items) {
void readVector(std::vector<AST_keyword*>& t, pypa::AstExprList& items, InternedStringPool& interned_strings) {
for (auto& item : items) {
assert(item->type == pypa::AstType::Keyword);
t.push_back(readItem(static_cast<pypa::AstKeyword&>(*item)));
t.push_back(readItem(static_cast<pypa::AstKeyword&>(*item), interned_strings));
}
}
template <typename T, typename U> void readVector(std::vector<T*>& t, std::vector<U>& u) {
template <typename T, typename U>
void readVector(std::vector<T*>& t, std::vector<U>& u, InternedStringPool& interned_strings) {
for (auto& item : u) {
if (!item) {
t.push_back(nullptr);
} else {
t.push_back(readItem(*item));
t.push_back(readItem(*item, interned_strings));
}
}
}
void readVector(std::vector<AST_expr*>& t, pypa::AstExpression& u) {
void readVector(std::vector<AST_expr*>& t, pypa::AstExpression& u, InternedStringPool& interned_strings) {
if (u.type == pypa::AstType::Tuple) {
pypa::AstTuple& e = static_cast<pypa::AstTuple&>(u);
for (auto& item : e.elements) {
assert(item);
t.push_back(readItem(*item));
t.push_back(readItem(*item, interned_strings));
}
} else {
t.push_back(readItem(u));
t.push_back(readItem(u, interned_strings));
}
}
void readVector(std::vector<AST_stmt*>& t, pypa::AstStatement& u) {
void readVector(std::vector<AST_stmt*>& t, pypa::AstStatement& u, InternedStringPool& interned_strings) {
if (u.type == pypa::AstType::Suite) {
pypa::AstSuite& e = static_cast<pypa::AstSuite&>(u);
for (auto& item : e.items) {
assert(item);
t.push_back(readItem(*item));
t.push_back(readItem(*item, interned_strings));
}
} else {
t.push_back(readItem(u));
t.push_back(readItem(u, interned_strings));
}
}
AST_comprehension* readItem(pypa::AstComprehension& c) {
AST_comprehension* readItem(pypa::AstComprehension& c, InternedStringPool& interned_strings) {
AST_comprehension* ptr = new AST_comprehension();
ptr->target = readItem(c.target);
ptr->iter = readItem(c.iter);
readVector(ptr->ifs, c.ifs);
ptr->target = readItem(c.target, interned_strings);
ptr->iter = readItem(c.iter, interned_strings);
readVector(ptr->ifs, c.ifs, interned_strings);
return ptr;
}
AST_comprehension* readItem(pypa::AstComprPtr c) {
AST_comprehension* readItem(pypa::AstComprPtr c, InternedStringPool& interned_strings) {
if (c)
return readItem(*c);
return readItem(*c, interned_strings);
return nullptr;
}
void readVector(std::vector<AST_comprehension*>& t, pypa::AstExprList& u) {
void readVector(std::vector<AST_comprehension*>& t, pypa::AstExprList& u, InternedStringPool& interned_strings) {
for (auto& e : u) {
assert(e && e->type == pypa::AstType::Comprehension);
t.push_back(readItem(static_cast<pypa::AstComprehension&>(*e)));
t.push_back(readItem(static_cast<pypa::AstComprehension&>(*e), interned_strings));
}
}
void readVector(std::vector<AST_stmt*>& t, pypa::AstStmt u) {
void readVector(std::vector<AST_stmt*>& t, pypa::AstStmt u, InternedStringPool& interned_strings) {
if (u) {
readVector(t, *u);
readVector(t, *u, interned_strings);
}
}
AST_ExceptHandler* readItem(pypa::AstExcept& e) {
AST_ExceptHandler* readItem(pypa::AstExcept& e, InternedStringPool& interned_strings) {
AST_ExceptHandler* ptr = new AST_ExceptHandler();
location(ptr, e);
readVector(ptr->body, e.body);
ptr->name = readItem(e.name);
ptr->type = readItem(e.type);
readVector(ptr->body, e.body, interned_strings);
ptr->name = readItem(e.name, interned_strings);
ptr->type = readItem(e.type, interned_strings);
return ptr;
}
AST_ExceptHandler* readItem(pypa::AstExceptPtr ptr) {
AST_ExceptHandler* readItem(pypa::AstExceptPtr ptr, InternedStringPool& interned_strings) {
assert(ptr);
return readItem(*ptr);
return readItem(*ptr, interned_strings);
}
AST_alias* readItem(pypa::AstAlias& a) {
return new AST_alias(readName(a.name), readName(a.as_name));
AST_alias* readItem(pypa::AstAlias& a, InternedStringPool& interned_strings) {
return new AST_alias(readName(a.name, interned_strings), readName(a.as_name, interned_strings));
}
AST_arguments* readItem(pypa::AstArguments& a) {
AST_arguments* readItem(pypa::AstArguments& a, InternedStringPool& interned_strings) {
AST_arguments* ptr = new AST_arguments();
location(ptr, a);
readVector(ptr->defaults, a.defaults);
readVector(ptr->defaults, a.defaults, interned_strings);
ptr->defaults.erase(std::remove(ptr->defaults.begin(), ptr->defaults.end(), nullptr), ptr->defaults.end());
readVector(ptr->args, a.arguments);
ptr->kwarg = readName(a.kwargs);
ptr->vararg = readName(a.args);
readVector(ptr->args, a.arguments, interned_strings);
ptr->kwarg = readName(a.kwargs, interned_strings);
ptr->vararg = readName(a.args, interned_strings);
return ptr;
}
struct expr_dispatcher {
InternedStringPool& interned_strings;
expr_dispatcher(InternedStringPool& interned_strings) : interned_strings(interned_strings) {}
typedef AST_expr* ResultPtr;
template <typename T> ResultPtr operator()(std::shared_ptr<T> t) {
if (t)
......@@ -304,8 +312,8 @@ struct expr_dispatcher {
ResultPtr read(pypa::AstAttribute& a) {
AST_Attribute* ptr = new AST_Attribute();
location(ptr, a);
ptr->value = readItem(a.value);
ptr->attr = readName(a.attribute);
ptr->value = readItem(a.value, interned_strings);
ptr->attr = readName(a.attribute, interned_strings);
ptr->ctx_type = readItem(a.context);
return ptr;
}
......@@ -314,7 +322,7 @@ struct expr_dispatcher {
AST_BoolOp* ptr = new AST_BoolOp();
location(ptr, b);
ptr->op_type = readItem(b.op);
readVector(ptr->values, b.values);
readVector(ptr->values, b.values, interned_strings);
return ptr;
}
......@@ -322,31 +330,31 @@ struct expr_dispatcher {
AST_BinOp* ptr = new AST_BinOp();
location(ptr, b);
ptr->op_type = readItem(b.op);
ptr->left = readItem(b.left);
ptr->right = readItem(b.right);
ptr->left = readItem(b.left, interned_strings);
ptr->right = readItem(b.right, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstCall& c) {
AST_Call* ptr = new AST_Call();
location(ptr, c);
readVector(ptr->args, c.arglist.arguments);
readVector(ptr->keywords, c.arglist.keywords);
ptr->func = readItem(c.function);
ptr->starargs = readItem(c.arglist.args);
ptr->kwargs = readItem(c.arglist.kwargs);
readVector(ptr->args, c.arglist.arguments, interned_strings);
readVector(ptr->keywords, c.arglist.keywords, interned_strings);
ptr->func = readItem(c.function, interned_strings);
ptr->starargs = readItem(c.arglist.args, interned_strings);
ptr->kwargs = readItem(c.arglist.kwargs, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstCompare& c) {
AST_Compare* ptr = new AST_Compare();
location(ptr, c);
ptr->left = readItem(c.left);
ptr->left = readItem(c.left, interned_strings);
ptr->ops.reserve(c.operators.size());
for (auto op : c.operators) {
ptr->ops.push_back(readItem(op));
}
readVector(ptr->comparators, c.comparators);
readVector(ptr->comparators, c.comparators, interned_strings);
return ptr;
}
......@@ -365,17 +373,17 @@ struct expr_dispatcher {
ResultPtr read(pypa::AstDict& d) {
AST_Dict* ptr = new AST_Dict();
location(ptr, d);
readVector(ptr->keys, d.keys);
readVector(ptr->values, d.values);
readVector(ptr->keys, d.keys, interned_strings);
readVector(ptr->values, d.values, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstDictComp& d) {
AST_DictComp* ptr = new AST_DictComp();
location(ptr, d);
ptr->key = readItem(d.key);
ptr->value = readItem(d.value);
readVector(ptr->generators, d.generators);
ptr->key = readItem(d.key, interned_strings);
ptr->value = readItem(d.value, interned_strings);
readVector(ptr->generators, d.generators, interned_strings);
return ptr;
}
......@@ -388,46 +396,46 @@ struct expr_dispatcher {
ResultPtr read(pypa::AstExtSlice& e) {
AST_ExtSlice* ptr = new AST_ExtSlice();
location(ptr, e);
readVector(ptr->dims, e.dims);
readVector(ptr->dims, e.dims, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstIfExpr& i) {
AST_IfExp* ptr = new AST_IfExp();
location(ptr, i);
ptr->body = readItem(i.body);
ptr->test = readItem(i.test);
ptr->orelse = readItem(i.orelse);
ptr->body = readItem(i.body, interned_strings);
ptr->test = readItem(i.test, interned_strings);
ptr->orelse = readItem(i.orelse, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstGenerator& g) {
AST_GeneratorExp* ptr = new AST_GeneratorExp();
location(ptr, g);
ptr->elt = readItem(g.element);
readVector(ptr->generators, g.generators);
ptr->elt = readItem(g.element, interned_strings);
readVector(ptr->generators, g.generators, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstIndex& i) {
AST_Index* ptr = new AST_Index();
location(ptr, i);
ptr->value = readItem(i.value);
ptr->value = readItem(i.value, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstLambda& l) {
AST_Lambda* ptr = new AST_Lambda();
location(ptr, l);
ptr->args = readItem(l.arguments);
ptr->body = readItem(l.body);
ptr->args = readItem(l.arguments, interned_strings);
ptr->body = readItem(l.body, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstList& l) {
AST_List* ptr = new AST_List();
location(ptr, l);
readVector(ptr->elts, l.elements);
readVector(ptr->elts, l.elements, interned_strings);
ptr->ctx_type = readItem(l.context);
return ptr;
}
......@@ -435,18 +443,18 @@ struct expr_dispatcher {
ResultPtr read(pypa::AstListComp& l) {
AST_ListComp* ptr = new AST_ListComp();
location(ptr, l);
readVector(ptr->generators, l.generators);
ptr->elt = readItem(l.element);
readVector(ptr->generators, l.generators, interned_strings);
ptr->elt = readItem(l.element, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstName& a) {
AST_Name* ptr = new AST_Name(a.id, readItem(a.context), a.line, a.column);
AST_Name* ptr = new AST_Name(interned_strings.get(a.id), readItem(a.context), a.line, a.column);
return ptr;
}
ResultPtr read(pypa::AstNone& n) {
AST_Name* ptr = new AST_Name("None", AST_TYPE::Load, n.line, n.column);
AST_Name* ptr = new AST_Name(interned_strings.get("None"), AST_TYPE::Load, n.line, n.column);
return ptr;
}
......@@ -473,23 +481,23 @@ struct expr_dispatcher {
ResultPtr read(pypa::AstRepr& r) {
AST_Repr* ptr = new AST_Repr();
location(ptr, r);
ptr->value = readItem(r.value);
ptr->value = readItem(r.value, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstSet& s) {
AST_Set* ptr = new AST_Set();
location(ptr, s);
readVector(ptr->elts, s.elements);
readVector(ptr->elts, s.elements, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstSlice& s) {
AST_Slice* ptr = new AST_Slice();
location(ptr, s);
ptr->lower = readItem(s.lower);
ptr->upper = readItem(s.upper);
ptr->step = readItem(s.step);
ptr->lower = readItem(s.lower, interned_strings);
ptr->upper = readItem(s.upper, interned_strings);
ptr->step = readItem(s.step, interned_strings);
return ptr;
}
......@@ -503,16 +511,16 @@ struct expr_dispatcher {
ResultPtr read(pypa::AstSubscript& s) {
AST_Subscript* ptr = new AST_Subscript();
location(ptr, s);
ptr->value = readItem(s.value);
ptr->value = readItem(s.value, interned_strings);
ptr->ctx_type = readItem(s.context);
ptr->slice = readItem(s.slice);
ptr->slice = readItem(s.slice, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstTuple& t) {
AST_Tuple* ptr = new AST_Tuple();
location(ptr, t);
readVector(ptr->elts, t.elements);
readVector(ptr->elts, t.elements, interned_strings);
ptr->ctx_type = readItem(t.context);
return ptr;
}
......@@ -521,19 +529,22 @@ struct expr_dispatcher {
AST_UnaryOp* ptr = new AST_UnaryOp();
location(ptr, b);
ptr->op_type = readItem(b.op);
ptr->operand = readItem(b.operand);
ptr->operand = readItem(b.operand, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstYieldExpr& e) {
AST_Yield* ptr = new AST_Yield();
location(ptr, e);
ptr->value = readItem(e.args);
ptr->value = readItem(e.args, interned_strings);
return ptr;
}
};
struct stmt_dispatcher {
InternedStringPool& interned_strings;
stmt_dispatcher(InternedStringPool& interned_strings) : interned_strings(interned_strings) {}
typedef AST_stmt* ResultPtr;
template <typename T> ResultPtr operator()(std::shared_ptr<T> t) {
if (t)
......@@ -555,16 +566,16 @@ struct stmt_dispatcher {
ResultPtr read(pypa::AstAssign& a) {
AST_Assign* ptr = new AST_Assign();
location(ptr, a);
readVector(ptr->targets, a.targets);
ptr->value = readItem(a.value);
readVector(ptr->targets, a.targets, interned_strings);
ptr->value = readItem(a.value, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstAssert& a) {
AST_Assert* ptr = new AST_Assert();
location(ptr, a);
ptr->msg = readItem(a.expression);
ptr->test = readItem(a.test);
ptr->msg = readItem(a.expression, interned_strings);
ptr->test = readItem(a.test, interned_strings);
return ptr;
}
......@@ -572,8 +583,8 @@ struct stmt_dispatcher {
AST_AugAssign* ptr = new AST_AugAssign();
location(ptr, a);
ptr->op_type = readItem(a.op);
ptr->target = readItem(a.target);
ptr->value = readItem(a.value);
ptr->target = readItem(a.target, interned_strings);
ptr->value = readItem(a.value, interned_strings);
return ptr;
}
......@@ -587,10 +598,10 @@ struct stmt_dispatcher {
AST_ClassDef* ptr = new AST_ClassDef();
location(ptr, c);
if (c.bases)
readVector(ptr->bases, *c.bases);
readVector(ptr->decorator_list, c.decorators);
readVector(ptr->body, c.body);
ptr->name = readName(c.name);
readVector(ptr->bases, *c.bases, interned_strings);
readVector(ptr->decorator_list, c.decorators, interned_strings);
readVector(ptr->body, c.body, interned_strings);
ptr->name = readName(c.name, interned_strings);
return ptr;
}
......@@ -603,48 +614,48 @@ struct stmt_dispatcher {
ResultPtr read(pypa::AstDelete& d) {
AST_Delete* ptr = new AST_Delete();
location(ptr, d);
readVector(ptr->targets, *d.targets);
readVector(ptr->targets, *d.targets, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstExec& e) {
AST_Exec* ptr = new AST_Exec();
location(ptr, e);
ptr->body = readItem(e.body);
ptr->body = readItem(e.body, interned_strings);
if (e.globals)
ptr->globals = readItem(e.globals);
ptr->globals = readItem(e.globals, interned_strings);
if (e.locals)
ptr->locals = readItem(e.locals);
ptr->locals = readItem(e.locals, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstExpressionStatement& e) {
AST_Expr* ptr = new AST_Expr();
location(ptr, e);
ptr->value = readItem(e.expr);
ptr->value = readItem(e.expr, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstFor& f) {
AST_For* ptr = new AST_For();
location(ptr, f);
ptr->target = readItem(f.target);
ptr->target = readItem(f.target, interned_strings);
if (f.iter)
ptr->iter = readItem(f.iter);
ptr->iter = readItem(f.iter, interned_strings);
if (f.body)
readVector(ptr->body, *f.body);
readVector(ptr->body, *f.body, interned_strings);
if (f.orelse)
readVector(ptr->orelse, *f.orelse);
readVector(ptr->orelse, *f.orelse, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstFunctionDef& f) {
AST_FunctionDef* ptr = new AST_FunctionDef();
location(ptr, f);
readVector(ptr->decorator_list, f.decorators);
ptr->name = readName(f.name);
ptr->args = readItem(f.args);
readVector(ptr->body, f.body);
readVector(ptr->decorator_list, f.decorators, interned_strings);
ptr->name = readName(f.name, interned_strings);
ptr->args = readItem(f.args, interned_strings);
readVector(ptr->body, f.body, interned_strings);
return ptr;
}
......@@ -653,7 +664,7 @@ struct stmt_dispatcher {
location(ptr, g);
ptr->names.resize(g.names.size());
for (size_t i = 0; i < g.names.size(); ++i) {
ptr->names[i] = readName(*g.names[i]);
ptr->names[i] = readName(*g.names[i], interned_strings);
}
return ptr;
}
......@@ -661,10 +672,10 @@ struct stmt_dispatcher {
ResultPtr read(pypa::AstIf& i) {
AST_If* ptr = new AST_If();
location(ptr, i);
readVector(ptr->body, i.body);
ptr->test = readItem(i.test);
readVector(ptr->body, i.body, interned_strings);
ptr->test = readItem(i.test, interned_strings);
assert(ptr->test != 0);
readVector(ptr->orelse, i.orelse);
readVector(ptr->orelse, i.orelse, interned_strings);
return ptr;
}
......@@ -674,11 +685,11 @@ struct stmt_dispatcher {
if (i.names->type == pypa::AstType::Tuple) {
for (auto& name : static_cast<pypa::AstTuple&>(*i.names).elements) {
assert(name->type == pypa::AstType::Alias);
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*name)));
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*name), interned_strings));
}
} else {
assert(i.names->type == pypa::AstType::Alias);
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*i.names)));
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*i.names), interned_strings));
}
return ptr;
}
......@@ -686,15 +697,15 @@ struct stmt_dispatcher {
ResultPtr read(pypa::AstImportFrom& i) {
AST_ImportFrom* ptr = new AST_ImportFrom();
location(ptr, i);
ptr->module = readName(i.module);
ptr->module = readName(i.module, interned_strings);
if (i.names->type == pypa::AstType::Tuple) {
for (auto& name : static_cast<pypa::AstTuple&>(*i.names).elements) {
assert(name->type == pypa::AstType::Alias);
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*name)));
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*name), interned_strings));
}
} else {
assert(i.names->type == pypa::AstType::Alias);
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*i.names)));
ptr->names.push_back(readItem(static_cast<pypa::AstAlias&>(*i.names), interned_strings));
}
ptr->level = i.level;
return ptr;
......@@ -709,18 +720,18 @@ struct stmt_dispatcher {
ResultPtr read(pypa::AstPrint& p) {
AST_Print* ptr = new AST_Print();
location(ptr, p);
ptr->dest = readItem(p.destination);
ptr->dest = readItem(p.destination, interned_strings);
ptr->nl = p.newline;
readVector(ptr->values, p.values);
readVector(ptr->values, p.values, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstRaise& r) {
AST_Raise* ptr = new AST_Raise();
location(ptr, r);
ptr->arg0 = readItem(r.arg0);
ptr->arg1 = readItem(r.arg1);
ptr->arg2 = readItem(r.arg2);
ptr->arg0 = readItem(r.arg0, interned_strings);
ptr->arg1 = readItem(r.arg1, interned_strings);
ptr->arg2 = readItem(r.arg2, interned_strings);
return ptr;
}
......@@ -729,49 +740,49 @@ struct stmt_dispatcher {
ResultPtr read(pypa::AstReturn& r) {
AST_Return* ptr = new AST_Return();
location(ptr, r);
ptr->value = readItem(r.value);
ptr->value = readItem(r.value, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstTryExcept& t) {
AST_TryExcept* ptr = new AST_TryExcept();
location(ptr, t);
readVector(ptr->body, t.body);
readVector(ptr->orelse, t.orelse);
readVector(ptr->handlers, t.handlers);
readVector(ptr->body, t.body, interned_strings);
readVector(ptr->orelse, t.orelse, interned_strings);
readVector(ptr->handlers, t.handlers, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstTryFinally& t) {
AST_TryFinally* ptr = new AST_TryFinally();
location(ptr, t);
readVector(ptr->body, t.body);
readVector(ptr->finalbody, t.final_body);
readVector(ptr->body, t.body, interned_strings);
readVector(ptr->finalbody, t.final_body, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstWith& w) {
AST_With* ptr = new AST_With();
location(ptr, w);
ptr->optional_vars = readItem(w.optional);
ptr->context_expr = readItem(w.context);
readVector(ptr->body, w.body);
ptr->optional_vars = readItem(w.optional, interned_strings);
ptr->context_expr = readItem(w.context, interned_strings);
readVector(ptr->body, w.body, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstWhile& w) {
AST_While* ptr = new AST_While();
location(ptr, w);
ptr->test = readItem(w.test);
readVector(ptr->body, w.body);
readVector(ptr->orelse, w.orelse);
ptr->test = readItem(w.test, interned_strings);
readVector(ptr->body, w.body, interned_strings);
readVector(ptr->orelse, w.orelse, interned_strings);
return ptr;
}
ResultPtr read(pypa::AstYield& w) {
AST_Expr* ptr = new AST_Expr();
location(ptr, w);
ptr->value = readItem(w.yield);
ptr->value = readItem(w.yield, interned_strings);
return ptr;
}
......@@ -786,20 +797,20 @@ struct stmt_dispatcher {
}
};
AST_expr* readItem(pypa::AstExpression& e) {
return pypa::visit<AST_expr*>(expr_dispatcher(), e);
AST_expr* readItem(pypa::AstExpression& e, InternedStringPool& interned_strings) {
return pypa::visit<AST_expr*>(expr_dispatcher(interned_strings), e);
}
AST_stmt* readItem(pypa::AstStatement& s) {
return pypa::visit<AST_stmt*>(stmt_dispatcher(), s);
AST_stmt* readItem(pypa::AstStatement& s, InternedStringPool& interned_strings) {
return pypa::visit<AST_stmt*>(stmt_dispatcher(interned_strings), s);
}
AST_Module* readModule(pypa::AstModule& t) {
if (VERBOSITY("PYPA parsing") >= 2) {
printf("PYPA reading module\n");
}
AST_Module* mod = new AST_Module();
readVector(mod->body, t.body->items);
AST_Module* mod = new AST_Module(llvm::make_unique<InternedStringPool>());
readVector(mod->body, t.body->items, *mod->interned_strings);
return mod;
}
......
......@@ -967,7 +967,7 @@ void PrintVisitor::printIndent() {
bool PrintVisitor::visit_alias(AST_alias* node) {
printf("%s", node->name.c_str());
if (node->asname.size())
if (node->asname.str().size())
printf(" as %s", node->asname.c_str());
return true;
}
......
......@@ -24,6 +24,7 @@
#include "llvm/ADT/StringRef.h"
#include "core/common.h"
#include "core/stringpool.h"
namespace pyston {
......@@ -181,11 +182,11 @@ public:
class AST_alias : public AST {
public:
std::string name, asname;
InternedString name, asname;
virtual void accept(ASTVisitor* v);
AST_alias(const std::string& name, const std::string& asname) : AST(AST_TYPE::alias), name(name), asname(asname) {}
AST_alias(InternedString name, InternedString asname) : AST(AST_TYPE::alias), name(name), asname(asname) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::alias;
};
......@@ -197,7 +198,7 @@ public:
// These are represented as strings, not names; not sure why.
// If they don't exist, the string is empty.
std::string kwarg, vararg;
InternedString kwarg, vararg;
virtual void accept(ASTVisitor* v);
......@@ -262,14 +263,14 @@ class AST_Attribute : public AST_expr {
public:
AST_expr* value;
AST_TYPE::AST_TYPE ctx_type;
std::string attr;
InternedString attr;
virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v);
AST_Attribute() : AST_expr(AST_TYPE::Attribute) {}
AST_Attribute(AST_expr* value, AST_TYPE::AST_TYPE ctx_type, const std::string& attr)
AST_Attribute(AST_expr* value, AST_TYPE::AST_TYPE ctx_type, InternedString attr)
: AST_expr(AST_TYPE::Attribute), value(value), ctx_type(ctx_type), attr(attr) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Attribute;
......@@ -359,7 +360,7 @@ public:
std::vector<AST_expr*> bases, decorator_list;
std::vector<AST_stmt*> body;
std::string name;
InternedString name;
AST_ClassDef() : AST_stmt(AST_TYPE::ClassDef) {}
......@@ -490,7 +491,7 @@ class AST_FunctionDef : public AST_stmt {
public:
std::vector<AST_stmt*> body;
std::vector<AST_expr*> decorator_list;
std::string name;
InternedString name;
AST_arguments* args;
virtual void accept(ASTVisitor* v);
......@@ -516,7 +517,7 @@ public:
class AST_Global : public AST_stmt {
public:
std::vector<std::string> names;
std::vector<InternedString> names;
virtual void accept(ASTVisitor* v);
virtual void accept_stmt(StmtVisitor* v);
......@@ -565,7 +566,7 @@ public:
class AST_ImportFrom : public AST_stmt {
public:
std::string module;
InternedString module;
std::vector<AST_alias*> names;
int level;
......@@ -593,7 +594,7 @@ class AST_keyword : public AST {
public:
// no lineno, col_offset attributes
AST_expr* value;
std::string arg;
InternedString arg;
virtual void accept(ASTVisitor* v);
......@@ -643,12 +644,15 @@ public:
class AST_Module : public AST {
public:
std::unique_ptr<InternedStringPool> interned_strings;
// no lineno, col_offset attributes
std::vector<AST_stmt*> body;
virtual void accept(ASTVisitor* v);
AST_Module() : AST(AST_TYPE::Module) {}
AST_Module(std::unique_ptr<InternedStringPool> interned_strings)
: AST(AST_TYPE::Module), interned_strings(std::move(interned_strings)) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Module;
};
......@@ -656,12 +660,12 @@ public:
class AST_Name : public AST_expr {
public:
AST_TYPE::AST_TYPE ctx_type;
std::string id;
InternedString id;
virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v);
AST_Name(const std::string& id, AST_TYPE::AST_TYPE ctx_type, int lineno, int col_offset = 0)
AST_Name(InternedString id, AST_TYPE::AST_TYPE ctx_type, int lineno, int col_offset = 0)
: AST_expr(AST_TYPE::Name, lineno, col_offset), ctx_type(ctx_type), id(id) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Name;
......@@ -939,7 +943,7 @@ public:
class AST_ClsAttribute : public AST_expr {
public:
AST_expr* value;
std::string attr;
InternedString attr;
virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v);
......
......@@ -92,15 +92,19 @@ private:
CFGBlock* continue_dest, *break_dest, *return_dest;
bool say_why;
int did_why;
std::string why_name;
InternedString why_name;
RegionInfo(CFGBlock* continue_dest, CFGBlock* break_dest, CFGBlock* return_dest, bool say_why,
const std::string& why_name)
InternedString why_name)
: continue_dest(continue_dest), break_dest(break_dest), return_dest(return_dest), say_why(say_why),
did_why(0), why_name(why_name) {}
};
AST_Name* makeName(const std::string& id, AST_TYPE::AST_TYPE ctx_type, int lineno, int col_offset = 0) {
template <typename T> InternedString internString(T&& s) {
return source->getInternedStrings().get(std::forward<T>(s));
}
AST_Name* makeName(InternedString id, AST_TYPE::AST_TYPE ctx_type, int lineno, int col_offset = 0) {
AST_Name* name = new AST_Name(id, ctx_type, lineno, col_offset);
return name;
}
......@@ -109,24 +113,26 @@ private:
struct ExcBlockInfo {
CFGBlock* exc_dest;
std::string exc_type_name, exc_value_name, exc_traceback_name;
InternedString exc_type_name, exc_value_name, exc_traceback_name;
};
std::vector<ExcBlockInfo> exc_handlers;
void pushLoopRegion(CFGBlock* continue_dest, CFGBlock* break_dest) {
assert(continue_dest
!= break_dest); // I guess this doesn't have to be true, but validates passing say_why=false
regions.emplace_back(continue_dest, break_dest, nullptr, false, "");
regions.emplace_back(continue_dest, break_dest, nullptr, false, internString(""));
}
void pushFinallyRegion(CFGBlock* finally_block, const std::string& why_name) {
void pushFinallyRegion(CFGBlock* finally_block, InternedString why_name) {
regions.emplace_back(finally_block, finally_block, finally_block, true, why_name);
}
void popRegion() { regions.pop_back(); }
// XXX get rid of this
void pushReturnRegion(CFGBlock* return_dest) { regions.emplace_back(nullptr, nullptr, return_dest, false, ""); }
void pushReturnRegion(CFGBlock* return_dest) {
regions.emplace_back(nullptr, nullptr, return_dest, false, internString(""));
}
void doReturn(AST_expr* value) {
assert(value);
......@@ -138,7 +144,7 @@ private:
region.did_why |= (1 << Why::RETURN);
}
pushAssign(RETURN_NAME, value);
pushAssign(internString(RETURN_NAME), value);
AST_Jump* j = makeJump();
j->target = region.return_dest;
......@@ -218,16 +224,16 @@ private:
AST_expr* applyComprehensionCall(AST_DictComp* node, AST_Name* name) {
AST_expr* key = remapExpr(node->key);
AST_expr* value = remapExpr(node->value);
return makeCall(makeLoadAttribute(name, "__setitem__", true), key, value);
return makeCall(makeLoadAttribute(name, internString("__setitem__"), true), key, value);
}
AST_expr* applyComprehensionCall(AST_ListComp* node, AST_Name* name) {
AST_expr* elt = remapExpr(node->elt);
return makeCall(makeLoadAttribute(name, "append", true), elt);
return makeCall(makeLoadAttribute(name, internString("append"), true), elt);
}
template <typename ResultASTType, typename CompType> AST_expr* remapComprehension(CompType* node) {
std::string rtn_name = nodeName(node);
InternedString rtn_name = nodeName(node);
pushAssign(rtn_name, new ResultASTType());
std::vector<CFGBlock*> exit_blocks;
......@@ -244,13 +250,14 @@ private:
AST_expr* remapped_iter = remapExpr(c->iter);
AST_LangPrimitive* iter_call = new AST_LangPrimitive(AST_LangPrimitive::GET_ITER);
iter_call->args.push_back(remapped_iter);
std::string iter_name = nodeName(node, "lc_iter", i);
InternedString iter_name = nodeName(node, "lc_iter", i);
pushAssign(iter_name, iter_call);
// TODO bad to save these like this?
AST_expr* hasnext_attr
= makeLoadAttribute(makeName(iter_name, AST_TYPE::Load, node->lineno), "__hasnext__", true);
AST_expr* next_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load, node->lineno), "next", true);
AST_expr* hasnext_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load, node->lineno),
internString("__hasnext__"), true);
AST_expr* next_attr
= makeLoadAttribute(makeName(iter_name, AST_TYPE::Load, node->lineno), internString("next"), true);
AST_Jump* j;
......@@ -284,7 +291,7 @@ private:
push_back(br);
curblock = body_block;
std::string next_name(nodeName(next_attr));
InternedString next_name(nodeName(next_attr));
pushAssign(next_name, makeCall(next_attr));
pushAssign(c->target, makeName(next_name, AST_TYPE::Load, node->lineno));
......@@ -375,7 +382,7 @@ private:
return rtn;
}
AST_expr* makeLoadAttribute(AST_expr* base, const std::string& name, bool clsonly) {
AST_expr* makeLoadAttribute(AST_expr* base, InternedString name, bool clsonly) {
AST_expr* rtn;
if (clsonly) {
AST_ClsAttribute* attr = new AST_ClsAttribute();
......@@ -485,7 +492,7 @@ private:
push_back(assign);
for (int i = 0; i < elts->size(); i++) {
std::string tmp_name = nodeName(target, "", i);
InternedString tmp_name = nodeName(target, "", i);
new_target->elts.push_back(makeName(tmp_name, AST_TYPE::Store, target->lineno));
pushAssign((*elts)[i], makeName(tmp_name, AST_TYPE::Load, target->lineno));
......@@ -495,7 +502,7 @@ private:
}
}
void pushAssign(const std::string& id, AST_expr* val) {
void pushAssign(InternedString id, AST_expr* val) {
assert(val);
AST_expr* name = makeName(id, AST_TYPE::Store, val->lineno, 0);
pushAssign(name, val);
......@@ -511,7 +518,7 @@ private:
std::string nodeName(AST* node) {
InternedString nodeName(AST* node) {
char buf[40];
snprintf(buf, 40, "#%p", node);
// Uncomment this line to check to make sure we never reuse the same nodeName() accidentally.
......@@ -522,22 +529,22 @@ private:
static std::unordered_set<std::string> made;
assert(made.count(r) == 0);
made.insert(r);
return std::move(r);
return internString(std::move(r));
#else
return std::string(buf);
return internString(buf);
#endif
}
std::string nodeName(AST* node, const std::string& suffix) {
InternedString nodeName(AST* node, const std::string& suffix) {
char buf[50];
snprintf(buf, 50, "#%p_%s", node, suffix.c_str());
return std::string(buf);
return internString(std::string(buf));
}
std::string nodeName(AST* node, const std::string& suffix, int idx) {
InternedString nodeName(AST* node, const std::string& suffix, int idx) {
char buf[50];
snprintf(buf, 50, "#%p_%s_%d", node, suffix.c_str(), idx);
return std::string(buf);
return internString(std::string(buf));
}
AST_expr* remapAttribute(AST_Attribute* node) {
......@@ -604,7 +611,7 @@ private:
}
AST_expr* remapBoolOp(AST_BoolOp* node) {
std::string name = nodeName(node);
InternedString name = nodeName(node);
CFGBlock* starting_block = curblock;
CFGBlock* exit_block = cfg->addDeferredBlock();
......@@ -713,7 +720,7 @@ private:
}
return rtn;
} else {
std::string name = nodeName(node);
InternedString name = nodeName(node);
CFGBlock* exit_block = cfg->addDeferredBlock();
AST_expr* left = remapExpr(node->left);
......@@ -789,16 +796,16 @@ private:
AST_FunctionDef* func = new AST_FunctionDef();
func->lineno = node->lineno;
func->col_offset = node->col_offset;
std::string func_name(nodeName(func));
InternedString func_name(nodeName(func));
func->name = func_name;
scoping_analysis->registerScopeReplacement(node, func);
func->args = new AST_arguments();
func->args->vararg = "";
func->args->kwarg = "";
func->args->vararg = internString("");
func->args->kwarg = internString("");
std::string first_generator_name = nodeName(node->generators[0]);
InternedString first_generator_name = nodeName(node->generators[0]);
func->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
std::vector<AST_stmt*>* insert_point = &func->body;
......@@ -846,7 +853,7 @@ private:
};
AST_expr* remapIfExp(AST_IfExp* node) {
std::string rtn_name = nodeName(node);
InternedString rtn_name = nodeName(node);
AST_Branch* br = new AST_Branch();
br->col_offset = node->col_offset;
......@@ -1087,8 +1094,8 @@ private:
RELEASE_ASSERT(0, "%d", node->type);
}
if (wrap_with_assign && (rtn->type != AST_TYPE::Name || ast_cast<AST_Name>(rtn)->id[0] != '#')) {
std::string name = nodeName(node);
if (wrap_with_assign && (rtn->type != AST_TYPE::Name || ast_cast<AST_Name>(rtn)->id.str()[0] != '#')) {
InternedString name = nodeName(node);
pushAssign(name, rtn);
return makeName(name, AST_TYPE::Load, node->lineno);
} else {
......@@ -1131,9 +1138,9 @@ public:
assert(asgn->targets.size() == 1);
if (asgn->targets[0]->type == AST_TYPE::Name) {
AST_Name* target = ast_cast<AST_Name>(asgn->targets[0]);
if (target->id[0] != '#') {
if (target->id.str()[0] != '#') {
#ifndef NDEBUG
if (!(asgn->value->type == AST_TYPE::Name && ast_cast<AST_Name>(asgn->value)->id[0] == '#')
if (!(asgn->value->type == AST_TYPE::Name && ast_cast<AST_Name>(asgn->value)->id.str()[0] == '#')
&& asgn->value->type != AST_TYPE::Str && asgn->value->type != AST_TYPE::Num) {
fprintf(stdout, "\nError: doing a non-trivial assignment in an invoke is not allowed:\n");
print_ast(node);
......@@ -1143,7 +1150,7 @@ public:
#endif
curblock->push_back(node);
return;
} else if (asgn->value->type == AST_TYPE::Name && ast_cast<AST_Name>(asgn->value)->id[0] == '#') {
} else if (asgn->value->type == AST_TYPE::Name && ast_cast<AST_Name>(asgn->value)->id.str()[0] == '#') {
// Assigning from one temporary name to another:
curblock->push_back(node);
return;
......@@ -1268,32 +1275,32 @@ public:
static_cast<AST_Num*>(import->args[0])->num_type = AST_Num::INT;
static_cast<AST_Num*>(import->args[0])->n_int = -1;
import->args.push_back(new AST_LangPrimitive(AST_LangPrimitive::NONE));
import->args.push_back(new AST_Str(a->name));
import->args.push_back(new AST_Str(a->name.str()));
std::string tmpname = nodeName(a);
InternedString tmpname = nodeName(a);
pushAssign(tmpname, import);
if (a->asname.size() == 0) {
if (a->asname.str().size() == 0) {
// No asname, so load the top-level module into the name
// (e.g., for `import os.path`, loads the os module into `os`)
pushAssign(getTopModule(a->name), makeName(tmpname, AST_TYPE::Load, node->lineno));
pushAssign(internString(getTopModule(a->name.str())), makeName(tmpname, AST_TYPE::Load, node->lineno));
} else {
// If there is an asname, get the bottom-level module by
// getting the attributes and load it into asname.
int l = 0;
do {
int r = a->name.find('.', l);
int r = a->name.str().find('.', l);
if (r == std::string::npos) {
r = a->name.size();
r = a->name.str().size();
}
if (l == 0) {
l = r + 1;
continue;
}
pushAssign(tmpname, new AST_Attribute(makeName(tmpname, AST_TYPE::Load, node->lineno),
AST_TYPE::Load, a->name.substr(l, r)));
AST_TYPE::Load, internString(a->name.str().substr(l, r))));
l = r + 1;
} while (l < a->name.size());
} while (l < a->name.str().size());
pushAssign(a->asname, makeName(tmpname, AST_TYPE::Load, node->lineno));
}
}
......@@ -1322,15 +1329,15 @@ public:
import->args.push_back(new AST_Tuple());
static_cast<AST_Tuple*>(import->args[1])->ctx_type = AST_TYPE::Load;
for (int i = 0; i < node->names.size(); i++) {
static_cast<AST_Tuple*>(import->args[1])->elts.push_back(new AST_Str(node->names[i]->name));
static_cast<AST_Tuple*>(import->args[1])->elts.push_back(new AST_Str(node->names[i]->name.str()));
}
import->args.push_back(new AST_Str(node->module));
import->args.push_back(new AST_Str(node->module.str()));
std::string tmp_module_name = nodeName(node);
InternedString tmp_module_name = nodeName(node);
pushAssign(tmp_module_name, import);
for (AST_alias* a : node->names) {
if (a->name == "*") {
if (a->name.str() == "*") {
AST_LangPrimitive* import_star = new AST_LangPrimitive(AST_LangPrimitive::IMPORT_STAR);
import_star->lineno = node->lineno;
......@@ -1346,11 +1353,11 @@ public:
import_from->lineno = node->lineno;
import_from->col_offset = node->col_offset;
import_from->args.push_back(makeName(tmp_module_name, AST_TYPE::Load, node->lineno));
import_from->args.push_back(new AST_Str(a->name));
import_from->args.push_back(new AST_Str(a->name.str()));
std::string tmp_import_name = nodeName(a);
InternedString tmp_import_name = nodeName(a);
pushAssign(tmp_import_name, import_from);
pushAssign(a->asname.size() ? a->asname : a->name,
pushAssign(a->asname.str().size() ? a->asname : a->name,
makeName(tmp_import_name, AST_TYPE::Load, node->lineno));
}
}
......@@ -1446,7 +1453,7 @@ public:
case AST_TYPE::Name: {
AST_Name* n = ast_cast<AST_Name>(node->target);
assert(n->ctx_type == AST_TYPE::Store);
std::string n_name(nodeName(n));
InternedString n_name(nodeName(n));
pushAssign(n_name, makeName(n->id, AST_TYPE::Load, node->lineno));
remapped_target = n;
remapped_lhs = makeName(n_name, AST_TYPE::Load, node->lineno);
......@@ -1507,7 +1514,7 @@ public:
binop->col_offset = node->col_offset;
binop->lineno = node->lineno;
std::string node_name(nodeName(node));
InternedString node_name(nodeName(node));
pushAssign(node_name, binop);
pushAssign(remapped_target, makeName(node_name, AST_TYPE::Load, node->lineno));
return true;
......@@ -1605,7 +1612,7 @@ public:
AST_expr* value = remapExpr(node->value);
if (value == NULL)
value = makeName("None", AST_TYPE::Load, node->lineno);
value = makeName(internString("None"), AST_TYPE::Load, node->lineno);
doReturn(value);
return true;
}
......@@ -1760,12 +1767,15 @@ public:
char itername_buf[80];
snprintf(itername_buf, 80, "#iter_%p", node);
pushAssign(itername_buf, iter_call);
InternedString itername = internString(itername_buf);
pushAssign(itername, iter_call);
auto hasnext_attr = [&]() {
return makeLoadAttribute(makeName(itername_buf, AST_TYPE::Load, node->lineno), "__hasnext__", true);
return makeLoadAttribute(makeName(itername, AST_TYPE::Load, node->lineno), internString("__hasnext__"),
true);
};
AST_expr* next_attr = makeLoadAttribute(makeName(itername_buf, AST_TYPE::Load, node->lineno), "next", true);
AST_expr* next_attr
= makeLoadAttribute(makeName(itername, AST_TYPE::Load, node->lineno), internString("next"), true);
CFGBlock* test_block = cfg->addBlock();
AST_Jump* jump_to_test = makeJump();
......@@ -1806,7 +1816,7 @@ public:
pushLoopRegion(test_block, end_block);
curblock = loop_block;
std::string next_name(nodeName(next_attr));
InternedString next_name(nodeName(next_attr));
pushAssign(next_name, makeCall(next_attr));
pushAssign(node->target, makeName(next_name, AST_TYPE::Load, node->lineno));
......@@ -1896,9 +1906,9 @@ public:
assert(node->handlers.size() > 0);
CFGBlock* exc_handler_block = cfg->addDeferredBlock();
std::string exc_type_name = nodeName(node, "type");
std::string exc_value_name = nodeName(node, "value");
std::string exc_traceback_name = nodeName(node, "traceback");
InternedString exc_type_name = nodeName(node, "type");
InternedString exc_value_name = nodeName(node, "value");
InternedString exc_traceback_name = nodeName(node, "traceback");
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name });
for (AST_stmt* subnode : node->body) {
......@@ -2010,10 +2020,10 @@ public:
bool visit_tryfinally(AST_TryFinally* node) override {
CFGBlock* exc_handler_block = cfg->addDeferredBlock();
std::string exc_type_name = nodeName(node, "type");
std::string exc_value_name = nodeName(node, "value");
std::string exc_traceback_name = nodeName(node, "traceback");
std::string exc_why_name = nodeName(node, "why");
InternedString exc_type_name = nodeName(node, "type");
InternedString exc_value_name = nodeName(node, "value");
InternedString exc_traceback_name = nodeName(node, "traceback");
InternedString exc_why_name = nodeName(node, "why");
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name });
CFGBlock* finally_block = cfg->addDeferredBlock();
......@@ -2079,7 +2089,7 @@ public:
push_back(br);
curblock = doreturn;
doReturn(makeName(RETURN_NAME, AST_TYPE::Load, node->lineno));
doReturn(makeName(internString(RETURN_NAME), AST_TYPE::Load, node->lineno));
curblock = otherwise;
}
......@@ -2163,14 +2173,19 @@ public:
bool visit_with(AST_With* node) override {
char ctxmgrname_buf[80];
snprintf(ctxmgrname_buf, 80, "#ctxmgr_%p", node);
InternedString ctxmgrname = internString(ctxmgrname_buf);
char exitname_buf[80];
snprintf(exitname_buf, 80, "#exit_%p", node);
InternedString exitname = internString(exitname_buf);
InternedString nonename = internString("None");
pushAssign(ctxmgrname_buf, remapExpr(node->context_expr));
pushAssign(ctxmgrname, remapExpr(node->context_expr));
AST_expr* enter = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load, node->lineno), "__enter__", true);
AST_expr* exit = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load, node->lineno), "__exit__", true);
pushAssign(exitname_buf, exit);
AST_expr* enter
= makeLoadAttribute(makeName(ctxmgrname, AST_TYPE::Load, node->lineno), internString("__enter__"), true);
AST_expr* exit
= makeLoadAttribute(makeName(ctxmgrname, AST_TYPE::Load, node->lineno), internString("__exit__"), true);
pushAssign(exitname, exit);
enter = remapExpr(makeCall(enter));
if (node->optional_vars) {
......@@ -2199,10 +2214,10 @@ public:
popRegion(); // for the retrun
AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
AST_Call* exit_call = makeCall(makeName(exitname, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
push_back(makeExpr(exit_call));
CFGBlock* orig_ending_block = curblock;
......@@ -2214,10 +2229,10 @@ public:
} else {
curblock = continue_dest;
AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
AST_Call* exit_call = makeCall(makeName(exitname, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
push_back(makeExpr(exit_call));
cfg->placeBlock(continue_dest);
......@@ -2229,10 +2244,10 @@ public:
} else {
curblock = break_dest;
AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
AST_Call* exit_call = makeCall(makeName(exitname, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
push_back(makeExpr(exit_call));
cfg->placeBlock(break_dest);
......@@ -2247,13 +2262,13 @@ public:
cfg->placeBlock(return_dest);
curblock = return_dest;
AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName("None", AST_TYPE::Load, node->lineno));
AST_Call* exit_call = makeCall(makeName(exitname, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
exit_call->args.push_back(makeName(nonename, AST_TYPE::Load, node->lineno));
push_back(makeExpr(exit_call));
doReturn(makeName(RETURN_NAME, AST_TYPE::Load, node->lineno));
doReturn(makeName(internString(RETURN_NAME), AST_TYPE::Load, node->lineno));
curblock = orig_ending_block;
}
......@@ -2304,7 +2319,8 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
Box* module_name = source->parent_module->getattr("__name__", NULL);
assert(module_name->cls == str_cls);
AST_Assign* module_assign = new AST_Assign();
module_assign->targets.push_back(new AST_Name("__module__", AST_TYPE::Store, source->ast->lineno));
module_assign->targets.push_back(
new AST_Name(source->getInternedStrings().get("__module__"), AST_TYPE::Store, source->ast->lineno));
module_assign->value = new AST_Str(static_cast<BoxedString*>(module_name)->s);
module_assign->lineno = 0;
visitor.push_back(module_assign);
......@@ -2314,7 +2330,8 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
AST_Expr* first_expr = ast_cast<AST_Expr>(body[0]);
if (first_expr->value->type == AST_TYPE::Str) {
AST_Assign* doc_assign = new AST_Assign();
doc_assign->targets.push_back(new AST_Name("__doc__", AST_TYPE::Store, source->ast->lineno));
doc_assign->targets.push_back(
new AST_Name(source->getInternedStrings().get("__doc__"), AST_TYPE::Store, source->ast->lineno));
doc_assign->value = first_expr->value;
doc_assign->lineno = 0;
visitor.push_back(doc_assign);
......
......@@ -31,6 +31,7 @@
#include "core/ast.h"
#include "core/common.h"
#include "core/stringpool.h"
namespace pyston {
......
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PYSTON_CORE_STRINGPOOL_H
#define PYSTON_CORE_STRINGPOOL_H
#include <algorithm>
#include <cstdio>
#include <sys/time.h>
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "core/common.h"
namespace std {
template <> struct hash<llvm::StringRef> {
size_t operator()(const llvm::StringRef s) const { return llvm::hash_value(s); }
};
}
namespace pyston {
class InternedStringPool;
class InternedString {
private:
const std::string* _str;
#ifndef NDEBUG
// Only for testing purposes:
InternedStringPool* pool;
InternedString(const std::string* str, InternedStringPool* pool) : _str(str), pool(pool) {}
#else
InternedString(const std::string* str) : _str(str) {}
#endif
public:
#ifndef NDEBUG
InternedString() : _str(NULL), pool(NULL) {}
#else
InternedString() : _str(NULL) {}
#endif
// operator const std::string&() { return *_str; }
const std::string& str() const {
assert(this->_str);
return *_str;
}
const char* c_str() const {
assert(this->_str);
return _str->c_str();
}
bool operator==(InternedString rhs) const {
assert(this->_str);
assert(this->pool == rhs.pool);
return this->_str == rhs._str;
}
bool operator<(InternedString rhs) const {
assert(this->_str);
assert(this->pool == rhs.pool);
return this->_str < rhs._str;
}
friend class InternedStringPool;
friend struct std::hash<InternedString>;
friend struct std::less<InternedString>;
};
class InternedStringPool {
private:
// We probably don't need to pull in llvm::StringRef as the key, but it's better than std::string
// which I assume forces extra allocations.
// (We could define a custom string-pointer container but is it worth it?)
std::unordered_map<llvm::StringRef, std::string*> interned;
public:
~InternedStringPool() {
for (auto& p : interned) {
delete p.second;
}
}
template <class T> InternedString get(T&& arg) {
auto it = interned.find(llvm::StringRef(arg));
std::string* s;
if (it != interned.end()) {
s = it->second;
} else {
s = new std::string(std::forward<T>(arg));
interned.insert(it, std::make_pair(llvm::StringRef(*s), s));
}
#ifndef NDEBUG
return InternedString(s, this);
#else
return InternedString(s);
#endif
}
};
} // namespace pyston
namespace std {
template <> struct hash<pyston::InternedString> {
size_t operator()(const pyston::InternedString s) const { return reinterpret_cast<intptr_t>(s._str) >> 3; }
};
template <> struct less<pyston::InternedString> {
bool operator()(const pyston::InternedString lhs, const pyston::InternedString rhs) const {
assert(lhs.pool && lhs.pool == rhs.pool);
// TODO: we should be able to do this comparison on the pointer value, not on the string value,
// but there are apparently parts of the code that rely on string sorting being actually alphabetical.
// We could create a faster "consistent ordering but not alphabetical" comparator if it makes a difference.
return *lhs._str < *rhs._str;
}
};
}
#endif
......@@ -28,6 +28,7 @@
#include "core/common.h"
#include "core/stats.h"
#include "core/stringpool.h"
namespace llvm {
class Function;
......@@ -218,6 +219,7 @@ public:
class BoxedModule;
class ScopeInfo;
class InternedStringPool;
class SourceInfo {
public:
BoxedModule* parent_module;
......@@ -228,18 +230,20 @@ public:
PhiAnalysis* phis;
bool is_generator;
InternedStringPool& getInternedStrings();
ScopeInfo* getScopeInfo();
struct ArgNames {
const std::vector<AST_expr*>* args;
const std::string* vararg, *kwarg;
InternedString vararg, kwarg;
explicit ArgNames(AST* ast);
explicit ArgNames(AST* ast, ScopingAnalysis* scoping);
int totalParameters() const {
if (!args)
return 0;
return args->size() + (vararg->size() == 0 ? 0 : 1) + (kwarg->size() == 0 ? 0 : 1);
return args->size() + (vararg.str().size() == 0 ? 0 : 1) + (kwarg.str().size() == 0 ? 0 : 1);
}
};
......@@ -249,7 +253,7 @@ public:
const std::vector<AST_stmt*> body;
const std::string getName();
std::string mangleName(const std::string& id);
InternedString mangleName(InternedString id);
SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, AST* ast, const std::vector<AST_stmt*>& body);
};
......
......@@ -20,6 +20,7 @@
#include <sys/time.h>
#include "core/common.h"
#include "core/stringpool.h"
namespace pyston {
......@@ -52,7 +53,7 @@ bool endswith(const std::string& s, const std::string& pattern);
void removeDirectoryIfExists(const std::string& path);
template <class T1, class T2> void compareKeyset(T1* lhs, T2* rhs) {
std::vector<std::string> lv, rv;
std::vector<InternedString> lv, rv;
for (typename T1::iterator it = lhs->begin(); it != lhs->end(); it++) {
lv.push_back(it->first);
}
......@@ -63,8 +64,8 @@ template <class T1, class T2> void compareKeyset(T1* lhs, T2* rhs) {
std::sort(lv.begin(), lv.end());
std::sort(rv.begin(), rv.end());
std::vector<std::string> lextra(lv.size());
std::vector<std::string>::iterator diffend
std::vector<InternedString> lextra(lv.size());
std::vector<InternedString>::iterator diffend
= std::set_difference(lv.begin(), lv.end(), rv.begin(), rv.end(), lextra.begin());
lextra.resize(diffend - lextra.begin());
......@@ -77,7 +78,7 @@ template <class T1, class T2> void compareKeyset(T1* lhs, T2* rhs) {
good = false;
}
std::vector<std::string> rextra(rv.size());
std::vector<InternedString> rextra(rv.size());
diffend = std::set_difference(rv.begin(), rv.end(), lv.begin(), lv.end(), rextra.begin());
rextra.resize(diffend - rextra.begin());
......
......@@ -202,7 +202,7 @@ int main(int argc, char** argv) {
if (m->body.size() > 0 && m->body[0]->type == AST_TYPE::Expr) {
AST_Expr* e = ast_cast<AST_Expr>(m->body[0]);
AST_Call* c = new AST_Call();
AST_Name* r = new AST_Name("repr", AST_TYPE::Load, 0);
AST_Name* r = new AST_Name(m->interned_strings->get("repr"), AST_TYPE::Load, 0);
c->func = r;
c->starargs = NULL;
c->kwargs = NULL;
......
......@@ -60,10 +60,26 @@
namespace pyston {
// TODO should centralize all of these:
static const std::string _call_str("__call__"), _new_str("__new__"), _init_str("__init__"), _get_str("__get__");
static const std::string _getattr_str("__getattr__");
static const std::string _getattribute_str("__getattribute__");
static const std::string all_str("__all__");
static const std::string attr_str("__len__");
static const std::string call_str("__call__");
static const std::string contains_str("__contains__");
static const std::string delattr_str("__delattr__");
static const std::string delete_str("__delete__");
static const std::string delitem_str("__delitem__");
static const std::string getattribute_str("__getattribute__");
static const std::string getattr_str("__getattr__");
static const std::string getitem_str("__getitem__");
static const std::string get_str("__get__");
static const std::string hasnext_str("__hasnext__");
static const std::string init_str("__init__");
static const std::string iter_str("__iter__");
static const std::string new_str("__new__");
static const std::string none_str("None");
static const std::string repr_str("__repr__");
static const std::string setitem_str("__setitem__");
static const std::string set_str("__set__");
static const std::string str_str("__str__");
#if 0
void REWRITE_ABORTED(const char* reason) {
......@@ -615,8 +631,6 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite
if (rewrite_args)
rewrite_args->obj->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)cls);
static const std::string none_str("None");
RELEASE_ASSERT(attr != none_str || this == builtins_module, "can't assign to None");
if (cls->instancesHaveHCAttrs()) {
......@@ -1092,8 +1106,8 @@ return gotten;
// this function is useful for custom getattribute implementations that already know whether the descriptor
// came from the class or not.
Box* processDescriptorOrNull(Box* obj, Box* inst, Box* owner) {
Box* descr_r = callattrInternal(obj, &_get_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(2), inst, owner, NULL,
NULL, NULL);
Box* descr_r
= callattrInternal(obj, &get_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(2), inst, owner, NULL, NULL, NULL);
return descr_r;
}
......@@ -1155,7 +1169,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
// Don't need to pass icentry args, since we special-case __getattribtue__ and __getattr__ to use
// invalidation rather than guards
// TODO since you changed this to typeLookup you need to guard
Box* getattribute = typeLookup(obj->cls, "__getattribute__", NULL);
Box* getattribute = typeLookup(obj->cls, getattribute_str, NULL);
if (getattribute) {
// TODO this is a good candidate for interning?
Box* boxstr = boxString(attr);
......@@ -1223,14 +1237,14 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
if (rewrite_args) {
RewriterVar* r_descr_cls = r_descr->getAttr(BOX_CLS_OFFSET, Location::any());
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_descr_cls, Location::any());
_get_ = typeLookup(descr->cls, _get_str, &grewrite_args);
_get_ = typeLookup(descr->cls, get_str, &grewrite_args);
if (!grewrite_args.out_success) {
rewrite_args = NULL;
} else if (_get_) {
r_get = grewrite_args.out_rtn;
}
} else {
_get_ = typeLookup(descr->cls, _get_str, NULL);
_get_ = typeLookup(descr->cls, get_str, NULL);
}
// As an optimization, don't check for __set__ if we're in cls_only mode, since it won't matter.
......@@ -1240,12 +1254,12 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
if (rewrite_args) {
RewriterVar* r_descr_cls = r_descr->getAttr(BOX_CLS_OFFSET, Location::any());
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_descr_cls, Location::any());
_set_ = typeLookup(descr->cls, "__set__", &grewrite_args);
_set_ = typeLookup(descr->cls, set_str, &grewrite_args);
if (!grewrite_args.out_success) {
rewrite_args = NULL;
}
} else {
_set_ = typeLookup(descr->cls, "__set__", NULL);
_set_ = typeLookup(descr->cls, set_str, NULL);
}
// Call __get__(descr, obj, obj->cls)
......@@ -1341,14 +1355,14 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
if (rewrite_args) {
RewriterVar* r_val_cls = r_val->getAttr(BOX_CLS_OFFSET, Location::any());
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_val_cls, Location::any());
local_get = typeLookup(val->cls, _get_str, &grewrite_args);
local_get = typeLookup(val->cls, get_str, &grewrite_args);
if (!grewrite_args.out_success) {
rewrite_args = NULL;
} else if (local_get) {
r_get = grewrite_args.out_rtn;
}
} else {
local_get = typeLookup(val->cls, _get_str, NULL);
local_get = typeLookup(val->cls, get_str, NULL);
}
// Call __get__(val, None, obj)
......@@ -1441,7 +1455,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
// invalidation rather than guards
rewrite_args = NULL;
REWRITE_ABORTED("");
Box* getattr = typeLookup(obj->cls, "__getattr__", NULL);
Box* getattr = typeLookup(obj->cls, getattr_str, NULL);
if (getattr) {
Box* boxstr = boxString(attr);
Box* rtn = runtimeCall2(getattr, ArgPassSpec(2), obj, boxstr);
......@@ -1572,14 +1586,14 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
if (rewrite_args) {
RewriterVar* r_cls = r_descr->getAttr(BOX_CLS_OFFSET, Location::any());
GetattrRewriteArgs trewrite_args(rewrite_args->rewriter, r_cls, Location::any());
_set_ = typeLookup(descr->cls, "__set__", &trewrite_args);
_set_ = typeLookup(descr->cls, set_str, &trewrite_args);
if (!trewrite_args.out_success) {
rewrite_args = NULL;
} else if (_set_) {
r_set = trewrite_args.out_rtn;
}
} else {
_set_ = typeLookup(descr->cls, "__set__", NULL);
_set_ = typeLookup(descr->cls, set_str, NULL);
}
}
......@@ -1605,7 +1619,7 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
if (isSubclass(obj->cls, type_cls)) {
BoxedClass* self = static_cast<BoxedClass*>(obj);
if (attr == _getattr_str || attr == _getattribute_str) {
if (attr == getattr_str || attr == getattribute_str) {
if (rewrite_args)
REWRITE_ABORTED("");
// Will have to embed the clear in the IC, so just disable the patching for now:
......@@ -1757,7 +1771,6 @@ extern "C" BoxedString* str(Box* obj) {
slowpath_str.log();
if (obj->cls != str_cls) {
static const std::string str_str("__str__");
// TODO could do an IC optimization here (once we do rewrites here at all):
// if __str__ is objectStr, just guard on that and call repr directly.
obj = callattrInternal(obj, &str_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
......@@ -1773,7 +1786,6 @@ extern "C" BoxedString* repr(Box* obj) {
static StatCounter slowpath_repr("slowpath_repr");
slowpath_repr.log();
static const std::string repr_str("__repr__");
obj = callattrInternal(obj, &repr_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
if (obj->cls != str_cls) {
......@@ -1855,7 +1867,6 @@ extern "C" BoxedInt* hash(Box* obj) {
extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
Box* rtn;
static std::string attr_str("__len__");
if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
rtn = callattrInternal0(obj, &attr_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0));
......@@ -2302,7 +2313,7 @@ static void placeKeyword(const std::vector<AST_expr*>& arg_names, std::vector<bo
continue;
AST_Name* n = ast_cast<AST_Name>(e);
if (n->id == kw_name) {
if (n->id.str() == kw_name) {
if (params_filled[j]) {
raiseExcHelper(TypeError, "%.200s() got multiple values for keyword argument '%s'",
getFunctionName(cl).c_str(), kw_name.c_str());
......@@ -2666,10 +2677,10 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
if (rewrite_args) {
// TODO is this ok?
// rewrite_args->rewriter->trap();
rtn = callattrInternal(obj, &_call_str, CLASS_ONLY, rewrite_args, argspec, arg1, arg2, arg3, args,
rtn = callattrInternal(obj, &call_str, CLASS_ONLY, rewrite_args, argspec, arg1, arg2, arg3, args,
keyword_names);
} else {
rtn = callattrInternal(obj, &_call_str, CLASS_ONLY, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
rtn = callattrInternal(obj, &call_str, CLASS_ONLY, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
}
if (!rtn)
raiseExcHelper(TypeError, "'%s' object is not callable", getTypeName(obj)->c_str());
......@@ -3032,16 +3043,14 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
if (op_type == AST_TYPE::In || op_type == AST_TYPE::NotIn) {
// TODO do rewrite
static const std::string str_contains("__contains__");
Box* contained = callattrInternal1(rhs, &str_contains, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
Box* contained = callattrInternal1(rhs, &contains_str, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
if (contained == NULL) {
static const std::string str_iter("__iter__");
Box* iter = callattrInternal0(rhs, &str_iter, CLASS_ONLY, NULL, ArgPassSpec(0));
Box* iter = callattrInternal0(rhs, &iter_str, CLASS_ONLY, NULL, ArgPassSpec(0));
if (iter)
ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs)->c_str());
RELEASE_ASSERT(iter == NULL, "need to try iterating");
Box* getitem = typeLookup(rhs->cls, "__getitem__", NULL);
Box* getitem = typeLookup(rhs->cls, getitem_str, NULL);
if (getitem)
ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs)->c_str());
RELEASE_ASSERT(getitem == NULL, "need to try old iteration protocol");
......@@ -3200,7 +3209,6 @@ extern "C" Box* getitem(Box* value, Box* slice) {
static StatCounter slowpath_getitem("slowpath_getitem");
slowpath_getitem.log();
static std::string str_getitem("__getitem__");
std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "getitem"));
......@@ -3210,14 +3218,14 @@ extern "C" Box* getitem(Box* value, Box* slice) {
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
rewrite_args.arg1 = rewriter->getArg(1);
rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, &rewrite_args, ArgPassSpec(1), slice);
rtn = callattrInternal1(value, &getitem_str, CLASS_ONLY, &rewrite_args, ArgPassSpec(1), slice);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
} else if (rtn)
rewriter->commitReturning(rewrite_args.out_rtn);
} else {
rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, NULL, ArgPassSpec(1), slice);
rtn = callattrInternal1(value, &getitem_str, CLASS_ONLY, NULL, ArgPassSpec(1), slice);
}
if (rtn == NULL) {
......@@ -3241,7 +3249,6 @@ extern "C" Box* getitem(Box* value, Box* slice) {
extern "C" void setitem(Box* target, Box* slice, Box* value) {
static StatCounter slowpath_setitem("slowpath_setitem");
slowpath_setitem.log();
static std::string str_setitem("__setitem__");
std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, "setitem"));
......@@ -3252,13 +3259,13 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
rewrite_args.arg1 = rewriter->getArg(1);
rewrite_args.arg2 = rewriter->getArg(2);
rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, &rewrite_args, ArgPassSpec(2), slice, value);
rtn = callattrInternal2(target, &setitem_str, CLASS_ONLY, &rewrite_args, ArgPassSpec(2), slice, value);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
}
} else {
rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, NULL, ArgPassSpec(2), slice, value);
rtn = callattrInternal2(target, &setitem_str, CLASS_ONLY, NULL, ArgPassSpec(2), slice, value);
}
if (rtn == NULL) {
......@@ -3274,7 +3281,6 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
extern "C" void delitem(Box* target, Box* slice) {
static StatCounter slowpath_delitem("slowpath_delitem");
slowpath_delitem.log();
static std::string str_delitem("__delitem__");
std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "delitem"));
......@@ -3284,14 +3290,14 @@ extern "C" void delitem(Box* target, Box* slice) {
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
rewrite_args.arg1 = rewriter->getArg(1);
rtn = callattrInternal1(target, &str_delitem, CLASS_ONLY, &rewrite_args, ArgPassSpec(1), slice);
rtn = callattrInternal1(target, &delitem_str, CLASS_ONLY, &rewrite_args, ArgPassSpec(1), slice);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
}
} else {
rtn = callattrInternal1(target, &str_delitem, CLASS_ONLY, NULL, ArgPassSpec(1), slice);
rtn = callattrInternal1(target, &delitem_str, CLASS_ONLY, NULL, ArgPassSpec(1), slice);
}
if (rtn == NULL) {
......@@ -3336,9 +3342,6 @@ void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) {
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs* rewrite_args) {
static const std::string delattr_str("__delattr__");
static const std::string delete_str("__delete__");
// custom __delattr__
if (allow_custom) {
Box* delAttr = typeLookup(obj->cls, delattr_str, NULL);
......@@ -3395,7 +3398,6 @@ extern "C" void delattr(Box* obj, const char* attr) {
extern "C" Box* getPystonIter(Box* o) {
Box* r = getiter(o);
static const std::string hasnext_str("__hasnext__");
if (typeLookup(r->cls, hasnext_str, NULL) == NULL)
return new BoxedIterWrapper(r);
return r;
......@@ -3403,12 +3405,10 @@ extern "C" Box* getPystonIter(Box* o) {
Box* getiter(Box* o) {
// TODO add rewriting to this? probably want to try to avoid this path though
static const std::string iter_str("__iter__");
Box* r = callattrInternal0(o, &iter_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(0));
if (r)
return r;
static const std::string getitem_str("__getitem__");
if (typeLookup(o->cls, getitem_str, NULL)) {
return new BoxedSeqIter(o);
}
......@@ -3578,7 +3578,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination);
// TODO: if tp_new != Py_CallPythonNew, call that instead?
new_attr = typeLookup(cls, _new_str, &grewrite_args);
new_attr = typeLookup(cls, new_str, &grewrite_args);
if (!grewrite_args.out_success)
rewrite_args = NULL;
......@@ -3598,7 +3598,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
}
}
} else {
new_attr = typeLookup(cls, _new_str, NULL);
new_attr = typeLookup(cls, new_str, NULL);
new_attr = processDescriptor(new_attr, None, cls);
}
assert(new_attr && "This should always resolve");
......@@ -3622,17 +3622,19 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
static Box* object_init = NULL;
static std::vector<Box*> allowable_news;
if (!object_new) {
object_new = typeLookup(object_cls, _new_str, NULL);
object_new = typeLookup(object_cls, new_str, NULL);
assert(object_new);
// I think this is unnecessary, but good form:
gc::registerPermanentRoot(object_new);
object_init = typeLookup(object_cls, _init_str, NULL);
object_init = typeLookup(object_cls, init_str, NULL);
assert(object_init);
gc::registerPermanentRoot(object_init);
allowable_news.push_back(object_new);
for (BoxedClass* allowed_cls : { enumerate_cls, xrange_cls }) {
auto new_obj = typeLookup(allowed_cls, _new_str, NULL);
auto new_obj = typeLookup(allowed_cls, new_str, NULL);
gc::registerPermanentRoot(new_obj);
allowable_news.push_back(new_obj);
}
......@@ -3665,7 +3667,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination);
init_attr = typeLookup(cls, _init_str, &grewrite_args);
init_attr = typeLookup(cls, init_str, &grewrite_args);
if (!grewrite_args.out_success)
rewrite_args = NULL;
......@@ -3676,7 +3678,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
}
}
} else {
init_attr = typeLookup(cls, _init_str, NULL);
init_attr = typeLookup(cls, init_str, NULL);
}
// The init_attr should always resolve as well, but doesn't yet
......@@ -3736,7 +3738,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
init_attr = NULL;
} else {
// We could have skipped the initial __init__ lookup
init_attr = typeLookup(made->cls, _init_str, NULL);
init_attr = typeLookup(made->cls, init_str, NULL);
}
}
......@@ -3811,14 +3813,14 @@ Box* typeCall(Box* obj, BoxedList* vararg) {
abort();
}
extern "C" void delGlobal(BoxedModule* m, std::string* name) {
extern "C" void delGlobal(BoxedModule* m, const std::string* name) {
if (!m->getattr(*name)) {
raiseExcHelper(NameError, "name '%s' is not defined", name->c_str());
}
m->delattr(*name, NULL);
}
extern "C" Box* getGlobal(BoxedModule* m, std::string* name) {
extern "C" Box* getGlobal(BoxedModule* m, const std::string* name) {
static StatCounter slowpath_getglobal("slowpath_getglobal");
slowpath_getglobal.log();
static StatCounter nopatch_getglobal("nopatch_getglobal");
......@@ -3909,8 +3911,6 @@ extern "C" Box* importStar(Box* _from_module, BoxedModule* to_module) {
assert(_from_module->cls == module_cls);
BoxedModule* from_module = static_cast<BoxedModule*>(_from_module);
static std::string all_str("__all__");
static std::string getitem_str("__getitem__");
Box* all = from_module->getattr(all_str);
if (all) {
......
......@@ -72,8 +72,8 @@ extern "C" BoxedInt* len(Box* obj);
extern "C" i64 unboxedLen(Box* obj);
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* augbinop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* getGlobal(BoxedModule* m, std::string* name);
extern "C" void delGlobal(BoxedModule* m, std::string* name);
extern "C" Box* getGlobal(BoxedModule* m, const std::string* name);
extern "C" void delGlobal(BoxedModule* m, const std::string* name);
extern "C" Box* getitem(Box* value, Box* slice);
extern "C" void setitem(Box* target, Box* slice, Box* value);
extern "C" void delitem(Box* target, Box* slice);
......
......@@ -508,7 +508,7 @@ BoxedClass* object_cls, *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls, *
BoxedTuple* EmptyTuple;
}
extern "C" Box* createUserClass(std::string* name, Box* _bases, Box* _attr_dict) {
extern "C" Box* createUserClass(const std::string* name, Box* _bases, Box* _attr_dict) {
ASSERT(_attr_dict->cls == dict_cls, "%s", getTypeName(_attr_dict)->c_str());
BoxedDict* attr_dict = static_cast<BoxedDict*>(_attr_dict);
......
......@@ -118,7 +118,7 @@ extern "C" void listAppendArrayInternal(Box* self, Box** v, int nelts);
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator,
std::initializer_list<Box*> defaults);
extern "C" CLFunction* unboxCLFunction(Box* b);
extern "C" Box* createUserClass(std::string* name, Box* base, Box* attr_dict);
extern "C" Box* createUserClass(const std::string* name, Box* base, Box* attr_dict);
extern "C" double unboxFloat(Box* b);
extern "C" Box* createDict();
extern "C" Box* createList();
......
......@@ -32,8 +32,8 @@ TEST_F(AnalysisTest, augassign) {
AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]);
ScopeInfo* scope_info = scoping->getScopeInfoForNode(func);
ASSERT_FALSE(scope_info->refersToGlobal("a"));
ASSERT_FALSE(scope_info->refersToGlobal("b"));
ASSERT_FALSE(scope_info->refersToGlobal(module->interned_strings->get("a")));
ASSERT_FALSE(scope_info->refersToGlobal(module->interned_strings->get("b")));
SourceInfo* si = new SourceInfo(createModule("__main__", fn), scoping, func, func->body);
......@@ -45,9 +45,9 @@ TEST_F(AnalysisTest, augassign) {
for (CFGBlock* block : cfg->blocks) {
//printf("%d\n", block->idx);
if (block->body.back()->type != AST_TYPE::Return)
ASSERT_TRUE(liveness->isLiveAtEnd("a", block));
ASSERT_TRUE(liveness->isLiveAtEnd(module->interned_strings->get("a"), block));
}
PhiAnalysis* phis = computeRequiredPhis(SourceInfo::ArgNames(func), cfg, liveness, scope_info);
PhiAnalysis* phis = computeRequiredPhis(SourceInfo::ArgNames(func, scoping), cfg, liveness, scope_info);
}
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