Commit faa290b8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Make 'is_generator' be a property of SourceInfo, not ScopeInfo

ScopeInfo involves checking the whole function subtree to resolve
scoping references.  SourceInfo has information about the specific
function.  is_generator used to be in ScopeInfo, but accessing it
would require doing the full subtree analysis, which can be
unnecessary.

This lets us avoid analyzing function subtrees that are never entered.
parent 2a50251c
......@@ -448,13 +448,11 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
case AST_TYPE::FunctionDef:
case AST_TYPE::Lambda: {
ScopeInfoBase* scopeInfo = new ScopeInfoBase(parent_info, usage);
scopeInfo->setTakesGenerator(containsYield(node));
this->scopes[node] = scopeInfo;
break;
}
case AST_TYPE::GeneratorExp: {
ScopeInfoBase* scopeInfo = new ScopeInfoBase(parent_info, usage);
scopeInfo->setTakesGenerator(true);
this->scopes[node] = scopeInfo;
break;
}
......
......@@ -24,7 +24,7 @@ class AST_Module;
class ScopeInfo {
public:
ScopeInfo() : isGeneratorValue(false) {}
ScopeInfo() {}
virtual ~ScopeInfo() {}
virtual ScopeInfo* getParent() = 0;
......@@ -32,9 +32,6 @@ public:
virtual bool takesClosure() = 0;
virtual bool passesThroughClosure() = 0;
virtual bool takesGenerator() { return isGeneratorValue; }
virtual void setTakesGenerator(bool b = true) { isGeneratorValue = b; }
virtual bool refersToGlobal(const std::string& name) = 0;
virtual bool refersToClosure(const std::string& name) = 0;
virtual bool saveInClosure(const std::string& name) = 0;
......@@ -43,9 +40,6 @@ public:
// the metaclass constructor.
// An error to call this on a non-classdef node.
virtual const std::unordered_set<std::string>& getClassDefLocalNames() = 0;
protected:
bool isGeneratorValue;
};
class ScopingAnalysis {
......
......@@ -136,6 +136,7 @@ public:
CompiledFunction* getCF() { return compiled_func; }
const SymMap& getSymbolTable() { return sym_table; }
void gcVisit(GCVisitor* visitor);
};
const void* interpreter_instr_addr = (void*)&ASTInterpreter::execute;
......@@ -201,11 +202,22 @@ BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
return rtn;
}
void ASTInterpreter::gcVisit(GCVisitor* visitor) {
for (const auto& p2 : getSymbolTable()) {
visitor->visitPotential(p2.second);
}
if (passed_closure)
visitor->visit(passed_closure);
if (created_closure)
visitor->visit(created_closure);
if (generator)
visitor->visit(generator);
}
void gatherInterpreterRoots(GCVisitor* visitor) {
for (const auto& p : s_interpreterMap) {
for (const auto& p2 : p.second->getSymbolTable()) {
visitor->visitPotential(p2.second);
}
p.second->gcVisit(visitor);
}
}
......@@ -633,11 +645,22 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v
u.d.ptr = &defaults[0];
u.d.s = defaults.size() - 1;
ScopeInfo* scope_info_node = source_info->scoping->getScopeInfoForNode(node);
bool is_generator = scope_info_node->takesGenerator();
bool takes_closure;
// Optimization: when compiling a module, it's nice to not have to run analyses into the
// entire module's source code.
// If we call getScopeInfoForNode, that will trigger an analysis of that function tree,
// but we're only using it here to figure out if that function takes a closure.
// Top level functions never take a closure, so we can skip the analysis.
if (source_info->ast->type == AST_TYPE::Module)
takes_closure = false;
else {
takes_closure = source_info->scoping->getScopeInfoForNode(node)->takesClosure();
}
bool is_generator = cl->source->is_generator;
BoxedClosure* closure = 0;
if (scope_info_node->takesClosure()) {
if (takes_closure) {
if (scope_info->createsClosure()) {
closure = created_closure;
} else {
......
......@@ -24,12 +24,31 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "analysis/scoping_analysis.h"
#include "core/ast.h"
#include "core/util.h"
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) {
switch (ast->type) {
case AST_TYPE::ClassDef:
case AST_TYPE::Lambda:
case AST_TYPE::Module:
is_generator = false;
break;
case AST_TYPE::FunctionDef:
is_generator = containsYield(ast);
break;
default:
RELEASE_ASSERT(0, "Unknown type: %d", ast->type);
break;
}
}
void FunctionAddressRegistry::registerFunction(const std::string& name, void* addr, int length,
llvm::Function* llvm_func) {
assert(addr);
......
......@@ -718,7 +718,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
if (source->getScopeInfo()->takesClosure())
names.insert(PASSED_CLOSURE_NAME);
if (source->getScopeInfo()->takesGenerator())
if (source->is_generator)
names.insert(PASSED_GENERATOR_NAME);
for (const auto& s : names) {
......@@ -1138,7 +1138,7 @@ CompiledFunction* doCompile(SourceInfo* source, const OSREntryDescriptor* entry_
if (source->getScopeInfo()->takesClosure())
llvm_arg_types.push_back(g.llvm_closure_type_ptr);
if (source->getScopeInfo()->takesGenerator())
if (source->is_generator)
llvm_arg_types.push_back(g.llvm_generator_type_ptr);
for (int i = 0; i < nargs; i++) {
......
......@@ -502,7 +502,7 @@ private:
assert(node->args[0]->type == AST_TYPE::Name);
RELEASE_ASSERT(irstate->getSourceInfo()->ast->type == AST_TYPE::Module,
"import * not supported in functions");
"import * not supported in functions (yet)");
CompilerVariable* module = evalExpr(node->args[0], unw_info);
ConcreteCompilerVariable* converted_module = module->makeConverted(emitter, module->getBoxType());
......@@ -1642,8 +1642,7 @@ private:
takes_closure = irstate->getScopeInfoForNode(node)->takesClosure();
}
// TODO: this lines disables the optimization mentioned above...
bool is_generator = irstate->getScopeInfoForNode(node)->takesGenerator();
bool is_generator = cl->source->is_generator;
if (takes_closure) {
if (irstate->getScopeInfo()->createsClosure()) {
......@@ -2362,7 +2361,7 @@ public:
_setFake(CREATED_CLOSURE_NAME, new ConcreteCompilerVariable(getCreatedClosureType(), new_closure, true));
}
if (scope_info->takesGenerator()) {
if (irstate->getSourceInfo()->is_generator) {
_setFake(PASSED_GENERATOR_NAME, new ConcreteCompilerVariable(GENERATOR, AI, true));
++AI;
}
......
......@@ -222,6 +222,7 @@ public:
CFG* cfg;
LivenessAnalysis* liveness;
PhiAnalysis* phis;
bool is_generator;
ScopeInfo* getScopeInfo();
......@@ -245,9 +246,7 @@ public:
const std::string getName();
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) {}
SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, AST* ast, const std::vector<AST_stmt*>& body);
};
typedef std::vector<CompiledFunction*> FunctionList;
......
# We need to be able to parse files with exec statements in them,
# even if we don't support the actual exec statement yet.
def dont_run_me():
exec "1/0"
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