Skip to content

Commit

Permalink
Add deferred reification (ponylang#2423)
Browse files Browse the repository at this point in the history
This change adds support for deferred reification to the compiler. This
allows AST reifications to be delayed until the reified version is
actually needed.

For now this is only used for the `lookup` function. In the future,
this will be used during code generation in order to avoid unnecessary
AST copying and to reduce the amount of simultaneous copies, as these
are the main culprits of the high memory usage of the compiler.
  • Loading branch information
Benoit Vey authored and jemc committed Dec 21, 2017
1 parent 8fbfbb3 commit abdcf2e
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 135 deletions.
7 changes: 4 additions & 3 deletions src/libponyc/codegen/genmatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ static bool static_match(compile_t* c, LLVMValueRef value, ast_t* type,
static ast_t* eq_param_type(compile_t* c, ast_t* pattern)
{
ast_t* pattern_type = ast_type(pattern);
ast_t* fun = lookup(NULL, pattern, pattern_type, c->str_eq);
deferred_reification_t* fun = lookup(NULL, pattern, pattern_type, c->str_eq);

AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, partial);
AST_GET_CHILDREN(fun->ast, cap, id, typeparams, params, result, partial);
ast_t* param = ast_child(params);
ast_t* type = ast_childidx(param, 1);

return ast_childidx(param, 1);
return deferred_reify(fun, type, c->opt);
}

static bool check_nominal(compile_t* c, LLVMValueRef desc, ast_t* pattern_type,
Expand Down
15 changes: 11 additions & 4 deletions src/libponyc/expr/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -674,9 +674,16 @@ static bool partial_application(pass_opt_t* opt, ast_t** astp)
}

// Look up the original method definition for this method call.
ast_t* method_def = lookup(opt, lhs, ast_type(receiver), ast_name(method));
pony_assert(ast_id(method_def) == TK_FUN || ast_id(method_def) == TK_BE ||
ast_id(method_def) == TK_NEW);
deferred_reification_t* method_def = lookup(opt, lhs, ast_type(receiver),
ast_name(method));
ast_t* method_ast = method_def->ast;

// The deferred reification doesn't own the underlying AST so we can free it
// safely.
deferred_reify_free(method_def);

pony_assert(ast_id(method_ast) == TK_FUN || ast_id(method_ast) == TK_BE ||
ast_id(method_ast) == TK_NEW);

// The TK_FUNTYPE of the LHS.
ast_t* type = ast_type(lhs);
Expand All @@ -693,7 +700,7 @@ static bool partial_application(pass_opt_t* opt, ast_t** astp)
if(!bare)
apply_cap = partial_application_cap(opt, type, receiver, positional);

token_id can_error = ast_id(ast_childidx(method_def, 5));
token_id can_error = ast_id(ast_childidx(method_ast, 5));
const char* recv_name = package_hygienic_id(t);

// Build lambda expression.
Expand Down
16 changes: 10 additions & 6 deletions src/libponyc/expr/match.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ static ast_t* make_pattern_type(pass_opt_t* opt, ast_t* pattern)
}

// Structural equality, pattern.eq(match).
ast_t* fun = lookup(opt, pattern, pattern_type, stringtab("eq"));
deferred_reification_t* fun = lookup(opt, pattern, pattern_type,
stringtab("eq"));

if(fun == NULL)
{
Expand All @@ -374,17 +375,19 @@ static ast_t* make_pattern_type(pass_opt_t* opt, ast_t* pattern)
return NULL;
}

if(ast_id(fun) != TK_FUN)
if(ast_id(fun->ast) != TK_FUN)
{
ast_error(opt->check.errors, pattern,
"eq is not a function on this pattern element");
ast_error_continue(opt->check.errors, fun,
ast_error_continue(opt->check.errors, fun->ast,
"definition of eq is here");
ast_free_unattached(fun);
deferred_reify_free(fun);
return NULL;
}

AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, partial);
ast_t* r_fun = deferred_reify_method_def(fun, fun->ast, opt);

AST_GET_CHILDREN(r_fun, cap, id, typeparams, params, result, partial);
bool ok = true;

if(ast_id(typeparams) != TK_NONE)
Expand Down Expand Up @@ -441,7 +444,8 @@ static ast_t* make_pattern_type(pass_opt_t* opt, ast_t* pattern)

ast_free_unattached(r_type);
ast_free_unattached(a_type);
ast_free_unattached(fun);
ast_free_unattached(r_fun);
deferred_reify_free(fun);

return pattern_type;
}
Expand Down
73 changes: 58 additions & 15 deletions src/libponyc/expr/postfix.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,7 @@ static bool constructor_type(pass_opt_t* opt, ast_t* ast, token_id cap,

static bool method_access(pass_opt_t* opt, ast_t* ast, ast_t* method)
{
AST_GET_CHILDREN(method, cap, id, typeparams, params, result, can_error,
body);
AST_GET_CHILDREN(method, cap, id, typeparams, params, result);

switch(ast_id(method))
{
Expand All @@ -142,6 +141,7 @@ static bool method_access(pass_opt_t* opt, ast_t* ast, ast_t* method)

if(!constructor_type(opt, ast, ast_id(cap), type, &result))
return false;

break;
}

Expand Down Expand Up @@ -178,14 +178,31 @@ static bool type_access(pass_opt_t* opt, ast_t** astp)
pony_assert(ast_id(left) == TK_TYPEREF);
pony_assert(ast_id(right) == TK_ID);

ast_t* find = lookup(opt, ast, type, ast_name(right));
deferred_reification_t* find = lookup(opt, ast, type, ast_name(right));

if(find == NULL)
return false;

ast_t* r_find = find->ast;

switch(ast_id(r_find))
{
case TK_FUN:
if(ast_id(ast_child(r_find)) != TK_AT)
break;
//fallthrough

case TK_NEW:
r_find = deferred_reify_method_def(find, r_find, opt);
break;

default:
break;
}

bool ret = true;

switch(ast_id(find))
switch(ast_id(r_find))
{
case TK_TYPEPARAM:
ast_error(opt->check.errors, right,
Expand All @@ -194,13 +211,13 @@ static bool type_access(pass_opt_t* opt, ast_t** astp)
break;

case TK_NEW:
ret = method_access(opt, ast, find);
ret = method_access(opt, ast, r_find);
break;

case TK_FUN:
if(ast_id(ast_child(find)) == TK_AT)
if(ast_id(ast_child(r_find)) == TK_AT)
{
ret = method_access(opt, ast, find);
ret = method_access(opt, ast, r_find);
break;
}
//fallthrough
Expand Down Expand Up @@ -246,7 +263,10 @@ static bool type_access(pass_opt_t* opt, ast_t** astp)
break;
}

ast_free_unattached(find);
if(r_find != find->ast)
ast_free_unattached(r_find);

deferred_reify_free(find);
return ret;
}

Expand Down Expand Up @@ -325,14 +345,34 @@ static bool member_access(pass_opt_t* opt, ast_t* ast)
if(is_typecheck_error(type))
return false;

ast_t* find = lookup(opt, ast, type, ast_name(right));
deferred_reification_t* find = lookup(opt, ast, type, ast_name(right));

if(find == NULL)
return false;

ast_t* r_find = find->ast;

switch(ast_id(r_find))
{
case TK_FVAR:
case TK_FLET:
case TK_EMBED:
r_find = deferred_reify(find, r_find, opt);
break;

case TK_NEW:
case TK_BE:
case TK_FUN:
r_find = deferred_reify_method_def(find, r_find, opt);
break;

default:
break;
}

bool ret = true;

switch(ast_id(find))
switch(ast_id(r_find))
{
case TK_TYPEPARAM:
ast_error(opt->check.errors, right,
Expand All @@ -341,24 +381,24 @@ static bool member_access(pass_opt_t* opt, ast_t* ast)
break;

case TK_FVAR:
if(!expr_fieldref(opt, ast, find, TK_FVARREF))
if(!expr_fieldref(opt, ast, r_find, TK_FVARREF))
return false;
break;

case TK_FLET:
if(!expr_fieldref(opt, ast, find, TK_FLETREF))
if(!expr_fieldref(opt, ast, r_find, TK_FLETREF))
return false;
break;

case TK_EMBED:
if(!expr_fieldref(opt, ast, find, TK_EMBEDREF))
if(!expr_fieldref(opt, ast, r_find, TK_EMBEDREF))
return false;
break;

case TK_NEW:
case TK_BE:
case TK_FUN:
ret = method_access(opt, ast, find);
ret = method_access(opt, ast, r_find);
break;

default:
Expand All @@ -367,7 +407,10 @@ static bool member_access(pass_opt_t* opt, ast_t* ast)
break;
}

ast_free_unattached(find);
if(r_find != find->ast)
ast_free_unattached(r_find);

deferred_reify_free(find);

return ret;
}
Expand Down
14 changes: 10 additions & 4 deletions src/libponyc/expr/reference.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,12 +626,15 @@ bool expr_addressof(pass_opt_t* opt, ast_t* ast)
if(ast_id(receiver) == ast_id(expr))
AST_GET_CHILDREN_NO_DECL(receiver, receiver, method);

ast_t* def = lookup(opt, expr, ast_type(receiver), ast_name(method));
pony_assert((ast_id(def) == TK_FUN) || (ast_id(def) == TK_BE));
deferred_reification_t* def = lookup(opt, expr, ast_type(receiver),
ast_name(method));
pony_assert((ast_id(def->ast) == TK_FUN) || (ast_id(def->ast) == TK_BE));

ast_t* r_def = deferred_reify_method_def(def, def->ast, opt);

// Set the type to a bare lambda type equivalent to the function type.
bool bare = ast_id(ast_child(def)) == TK_AT;
ast_t* params = ast_childidx(def, 3);
bool bare = ast_id(ast_child(r_def)) == TK_AT;
ast_t* params = ast_childidx(r_def, 3);
ast_t* result = ast_sibling(params);
ast_t* partial = ast_sibling(result);

Expand Down Expand Up @@ -666,6 +669,9 @@ bool expr_addressof(pass_opt_t* opt, ast_t* ast)
NODE(TK_VAL) // object cap
NONE)); // object cap mod

ast_free_unattached(r_def);
deferred_reify_free(def);

if(!ast_passes_subtree(&type, opt, PASS_EXPR))
return false;

Expand Down
16 changes: 13 additions & 3 deletions src/libponyc/pass/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,22 @@ ast_t* find_antecedent_type(pass_opt_t* opt, ast_t* ast, bool* is_recovered)
// we need to use the funtype of the apply method of the object.
if(ast_id(funtype) != TK_FUNTYPE)
{
ast_t* fun = lookup(opt, receiver, funtype, stringtab("apply"));
deferred_reification_t* fun = lookup(opt, receiver, funtype,
stringtab("apply"));

if((fun == NULL) || ((ast_id(fun) != TK_BE) && (ast_id(fun) != TK_FUN)))
if(fun == NULL)
return NULL;

funtype = type_for_fun(fun);
if((ast_id(fun->ast) != TK_BE) && (ast_id(fun->ast) != TK_FUN))
{
deferred_reify_free(fun);
return NULL;
}

ast_t* r_fun = deferred_reify_method_def(fun, fun->ast, opt);
funtype = type_for_fun(r_fun);
ast_free_unattached(r_fun);
deferred_reify_free(fun);
}

AST_GET_CHILDREN(funtype, cap, t_params, params, ret_type);
Expand Down
Loading

0 comments on commit abdcf2e

Please sign in to comment.