Skip to content

Commit

Permalink
add slow paths using heap allocation for handling large argument lists
Browse files Browse the repository at this point in the history
and large tuple types. fixes JuliaLang#10981
  • Loading branch information
JeffBezanson committed Apr 24, 2015
1 parent ec99e37 commit 0badae2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 44 deletions.
19 changes: 14 additions & 5 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,6 @@ JL_CALLABLE(jl_f_typeassert)
}

static jl_function_t *jl_append_any_func;
extern size_t jl_page_size;

JL_CALLABLE(jl_f_apply)
{
Expand Down Expand Up @@ -616,11 +615,21 @@ JL_CALLABLE(jl_f_tuple)
{
size_t i;
if (nargs == 0) return (jl_value_t*)jl_emptytuple;
jl_value_t **types = alloca(nargs*sizeof(jl_value_t*));
for(i=0; i < nargs; i++) {
types[i] = jl_typeof(args[i]);
jl_datatype_t *tt;
if (nargs < jl_page_size/sizeof(jl_value_t*)) {
jl_value_t **types = alloca(nargs*sizeof(jl_value_t*));
for(i=0; i < nargs; i++)
types[i] = jl_typeof(args[i]);
tt = jl_inst_concrete_tupletype_v(types, nargs);
}
else {
jl_svec_t *types = jl_alloc_svec_uninit(nargs);
JL_GC_PUSH1(&types);
for(i=0; i < nargs; i++)
jl_svecset(types, i, jl_typeof(args[i]));
tt = jl_inst_concrete_tupletype(types);
JL_GC_POP();
}
jl_datatype_t *tt = jl_inst_concrete_tupletype(types, nargs);
return jl_new_structv(tt, args, nargs);
}

Expand Down
38 changes: 27 additions & 11 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1404,18 +1404,34 @@ void NORETURN jl_no_method_error(jl_function_t *f, jl_value_t **args, size_t na)

static jl_tupletype_t *arg_type_tuple(jl_value_t **args, size_t nargs)
{
jl_value_t **types;
JL_GC_PUSHARGS(types, nargs);
jl_tupletype_t *tt;
size_t i;
for(i=0; i < nargs; i++) {
jl_value_t *ai = args[i];
if (jl_is_type(ai))
types[i] = (jl_value_t*)jl_wrap_Type(ai);
else
types[i] = jl_typeof(ai);
}
jl_tupletype_t *tt = (jl_tupletype_t*)jl_inst_concrete_tupletype(types, nargs);
JL_GC_POP();
if (nargs < jl_page_size/sizeof(jl_value_t*)) {
jl_value_t **types;
JL_GC_PUSHARGS(types, nargs);
for(i=0; i < nargs; i++) {
jl_value_t *ai = args[i];
if (jl_is_type(ai))
types[i] = (jl_value_t*)jl_wrap_Type(ai);
else
types[i] = jl_typeof(ai);
}
tt = (jl_tupletype_t*)jl_inst_concrete_tupletype_v(types, nargs);
JL_GC_POP();
}
else {
jl_svec_t *types = jl_alloc_svec(nargs);
JL_GC_PUSH1(&types);
for(i=0; i < nargs; i++) {
jl_value_t *ai = args[i];
if (jl_is_type(ai))
jl_svecset(types, i, (jl_value_t*)jl_wrap_Type(ai));
else
jl_svecset(types, i, jl_typeof(ai));
}
tt = (jl_tupletype_t*)jl_inst_concrete_tupletype(types);
JL_GC_POP();
}
return tt;
}

Expand Down
84 changes: 57 additions & 27 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2052,7 +2052,12 @@ DLLEXPORT jl_tupletype_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np)
return jl_apply_tuple_type_v_(p, np, NULL);
}

jl_datatype_t *jl_inst_concrete_tupletype(jl_value_t **p, size_t np)
jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p)
{
return (jl_datatype_t*)inst_datatype(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 1, 0, NULL, NULL, 0);
}

jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np)
{
return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, 0, NULL, NULL, 0);
}
Expand All @@ -2071,6 +2076,41 @@ static jl_svec_t *inst_all(jl_svec_t *p, jl_value_t **env, size_t n,
return np;
}

static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_value_t **env, size_t n,
jl_typestack_t *stack, int check)
{
jl_datatype_t *tt = (jl_datatype_t*)t;
jl_svec_t *tp = tt->parameters;
size_t ntp = jl_svec_len(tp);
jl_value_t **iparams;
int onstack = ntp < jl_page_size/sizeof(jl_value_t*);
JL_GC_PUSHARGS(iparams, onstack ? ntp : 1);
jl_svec_t *ip_heap=NULL;
if (!onstack) {
ip_heap = jl_alloc_svec(ntp);
iparams[0] = (jl_value_t*)ip_heap;
iparams = jl_svec_data(ip_heap);
}
int cacheable = 1, isabstract = 0;
if (jl_is_va_tuple(tt)) {
cacheable = 0; isabstract = 1;
}
int i;
for(i=0; i < ntp; i++) {
jl_value_t *elt = jl_svecref(tp, i);
iparams[i] = (jl_value_t*)inst_type_w_(elt, env, n, stack, 0);
if (!isabstract && !jl_is_leaf_type(iparams[i])) {
cacheable = 0; isabstract = 1;
}
if (cacheable && jl_has_typevars_(iparams[i],0))
cacheable = 0;
}
jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable, isabstract,
stack, env, n);
JL_GC_POP();
return result;
}

static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n,
jl_typestack_t *stack, int check)
{
Expand Down Expand Up @@ -2109,47 +2149,37 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n,
if (t == tc && stack!=NULL)
return (jl_value_t*)t;
assert(jl_is_datatype(tc));
if (tn == jl_tuple_typename)
return inst_tuple_w_(t, env, n, stack, check);
size_t ntp = jl_svec_len(tp);
assert(tn==jl_tuple_typename || ntp == jl_svec_len(((jl_datatype_t*)tc)->parameters));
assert(ntp == jl_svec_len(((jl_datatype_t*)tc)->parameters));
jl_value_t **iparams;
JL_GC_PUSHARGS(iparams, ntp);
int cacheable = 1, isabstract = 0, bound = 0;
if (tn == jl_tuple_typename && jl_is_va_tuple(tt)) {
cacheable = 0; isabstract = 1;
}
for(i=0; i < ntp; i++) {
jl_value_t *elt = jl_svecref(tp, i);
if (elt == t) {
iparams[i] = t;
}
else {
if (tn == jl_tuple_typename) {
iparams[i] = (jl_value_t*)inst_type_w_(elt, env, n, stack, 0);
if (!jl_is_leaf_type(iparams[i])) {
isabstract = 1;
cacheable = 0;
jl_value_t *tv = jl_svecref(((jl_datatype_t*)tc)->parameters, i);
iparams[i] = (jl_value_t*)inst_type_w_(elt, env, n, stack, elt != tv);
if (jl_is_typevar(tv) && !jl_is_typevar(iparams[i])) {
if (!jl_subtype(iparams[i], tv, 0)) {
jl_type_error_rt(tt->name->name->name,
((jl_tvar_t*)tv)->name->name,
tv, iparams[i]);
}
}
else {
jl_value_t *tv = jl_svecref(((jl_datatype_t*)tc)->parameters, i);
iparams[i] = (jl_value_t*)inst_type_w_(elt, env, n, stack, elt != tv);
if (jl_is_typevar(tv) && !jl_is_typevar(iparams[i])) {
if (!jl_subtype(iparams[i], tv, 0)) {
jl_type_error_rt(tt->name->name->name,
((jl_tvar_t*)tv)->name->name,
tv, iparams[i]);
}
}
if (!bound) {
for(j=0; j < n; j++) {
if (env[j*2] == tv) {
bound = 1; break;
}
if (!bound) {
for(j=0; j < n; j++) {
if (env[j*2] == tv) {
bound = 1; break;
}
}
if (jl_is_typevar(iparams[i]))
isabstract = 1;
}
if (jl_is_typevar(iparams[i]))
isabstract = 1;
}
if (jl_has_typevars_(iparams[i],0))
cacheable = 0;
Expand Down
5 changes: 4 additions & 1 deletion src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
extern "C" {
#endif

extern size_t jl_page_size;

STATIC_INLINE jl_value_t *newobj(jl_value_t *type, size_t nfields)
{
jl_value_t *jv = NULL;
Expand Down Expand Up @@ -78,7 +80,8 @@ int jl_subtype_invariant(jl_value_t *a, jl_value_t *b, int ta);
jl_value_t *jl_type_match(jl_value_t *a, jl_value_t *b);
jl_value_t *jl_type_match_morespecific(jl_value_t *a, jl_value_t *b);
int jl_types_equal_generic(jl_value_t *a, jl_value_t *b, int useenv);
jl_datatype_t *jl_inst_concrete_tupletype(jl_value_t **p, size_t np);
jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np);
jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p);

void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super);
void jl_initialize_generic_function(jl_function_t *f, jl_sym_t *name);
Expand Down

0 comments on commit 0badae2

Please sign in to comment.