Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions runtime/src/main/java/dev/ionfusion/fusion/LambdaForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,11 @@ SyntaxValue<?> expand(Expander expander, Environment env, SyntaxSexp stx)
var formals = children[1];
var args = flattenFormals(eval, check, formals);

// When there's no args, we can avoid an empty binding rib at runtime.
// TODO #67 This will need changing for internal definitions
// since we won't know yet whether the rib will be empty or not.
LocalEnvironment localEnv = null;
if (args.length != 0)
{
ensureUniqueIdentifiers(eval, args, stx);
env = localEnv = new LocalEnvironment(env, args);
env = localEnv = LocalEnvironment.forExpansion(env, args);
}

// Prepare the bound names so they resolve to their own binding.
Expand Down Expand Up @@ -149,11 +146,8 @@ CompiledForm compile(Compiler comp, Environment env, SyntaxSexp stx)

var formalsDecl = stx.get(eval, 1);
var formals = flattenFormals(eval, formalsDecl);
if (formals.length != 0)
{
// We micro-optimize by avoiding an environment frame for no-arg procedures.
env = LocalEnvironment.forBinders(env, formals);
}

env = LocalEnvironment.forCompilation(env, formals);

CompiledForm body = comp.compileBegin(env, stx, 2);

Expand Down Expand Up @@ -414,8 +408,7 @@ Object doApply(Evaluator eval, Object[] args)
{
checkArityExact(eval, myArity, args);

Store localStore = new LocalStore(myEnclosure, args);

Store localStore = LocalStore.forExecution(myEnclosure, args);
return eval.bounceTailForm(localStore, myBody);
}
}
Expand Down
12 changes: 4 additions & 8 deletions runtime/src/main/java/dev/ionfusion/fusion/LetValuesForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ SyntaxValue expand(Expander expander, Environment env, SyntaxSexp stx)
{
boundNames = boundNameList.toArray(SyntaxSymbol.EMPTY_ARRAY);
ensureUniqueIdentifiers(eval, boundNames, stx);
var localEnv = new LocalEnvironment(env, boundNames);
var localEnv = LocalEnvironment.forExpansion(env, boundNames);
localWrap = localEnv.getWrap();
bodyEnv = localEnv;
}
Expand Down Expand Up @@ -171,11 +171,7 @@ CompiledForm compile(Compiler comp, Environment env, SyntaxSexp expr)
valuePosns[i] = boundExpr.getPosition();
}

if (bindingCount != 0)
{
// Dummy environment to keep track of depth
env = LocalEnvironment.forBinders(env, binders.toArray(new SyntaxSymbol[0]));
}
env = LocalEnvironment.forCompilation(env, binders.toArray(new SyntaxSymbol[0]));

CompiledForm body = comp.compileBegin(env, expr, 2);

Expand Down Expand Up @@ -249,7 +245,7 @@ public Object doEval(Evaluator eval, Store store)
boundValues[i] = values;
}

Store localStore = new LocalStore(store, boundValues);
Store localStore = LocalStore.forExecution(store, boundValues);
return eval.bounceTailForm(localStore, myBody);
}
}
Expand Down Expand Up @@ -393,7 +389,7 @@ else if (values instanceof Object[])
}
}

Store localStore = LocalStore.forLocals(store, boundValues);
Store localStore = LocalStore.forExecution(store, boundValues);
return eval.bounceTailForm(localStore, myBody);
}
}
Expand Down
9 changes: 3 additions & 6 deletions runtime/src/main/java/dev/ionfusion/fusion/LetrecForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ SyntaxValue expand(Expander expander, Environment env, SyntaxSexp stx)
}
ensureUniqueIdentifiers(eval, boundNames, stx);

var bodyEnv = new LocalEnvironment(env, boundNames);
var bodyEnv = LocalEnvironment.forExpansion(env, boundNames);
SyntaxWrap localWrap = bodyEnv.getWrap();

// Expand the bound-value expressions
Expand Down Expand Up @@ -107,10 +107,7 @@ CompiledForm compile(Compiler comp, Environment env, SyntaxSexp stx)

var bindingForms = (SyntaxSequence) stx.get(eval, 1);
var binders = collectBinders(eval, bindingForms);
if (binders.length != 0)
{
env = LocalEnvironment.forBinders(env, binders);
}
env = LocalEnvironment.forCompilation(env, binders);

final int numBindings = binders.length;
CompiledForm [] valueForms = new CompiledForm [numBindings];
Expand Down Expand Up @@ -168,7 +165,7 @@ public Object doEval(Evaluator eval, Store store)
Object[] boundValues = new Object[numBindings];
Arrays.fill(boundValues, UNDEF);

Store localStore = new LocalStore(store, boundValues);
Store localStore = LocalStore.forExecution(store, boundValues);

for (int i = 0; i < numBindings; i++)
{
Expand Down
45 changes: 24 additions & 21 deletions runtime/src/main/java/dev/ionfusion/fusion/LocalEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,61 +130,64 @@ Binding resolveMaybe(BaseSymbol name,

/** Not null */
private final Environment myEnclosure;
private final Namespace myNamespace;
private final LocalBinding[] myBindings;
private final SyntaxWrap myWrap;


/**
* Expand-time environment construction.
*/
LocalEnvironment(Environment enclosure, SyntaxSymbol[] identifiers)
private LocalEnvironment(Environment enclosure,
LocalBinding[] bindings,
boolean makeWrap)
{
myEnclosure = enclosure;
myNamespace = enclosure.namespace();
myBindings = bindings;
myWrap = makeWrap ? new LocalEnvironmentWrap() : null;
}


/**
* Expand-time environment construction creates bindings for each identifier.
*/
static LocalEnvironment forExpansion(Environment enclosure,
SyntaxSymbol[] identifiers)
{
// 2019-04 Stats from the standard library and test suite:
// 85% of local envs have 1 entry, 12% have 2.
// 99% have 3 or fewer entries and none have more than 5.
int count = identifiers.length;
myBindings = new LocalBinding[count];
var bindings = new LocalBinding[count];
for (int i = 0; i < count; i++)
{
SyntaxSymbol identifier = identifiers[i];
myBindings[i] = new LocalBinding(identifier);
bindings[i] = new LocalBinding(identifier);
}

myWrap = new LocalEnvironmentWrap();
return new LocalEnvironment(enclosure, bindings, true);
}


/**
* Compile-time environment does not create bindings but uses them to
* determine access coordinates.
* Compile-time environment does not create bindings but uses them to determine
* variable addresses.
* <p>
* Logic for empty layers must mirror {@link LocalStore#forExecution}.
*/
private LocalEnvironment(Environment enclosure, LocalBinding[] bindings)
static Environment forCompilation(Environment enclosure, SyntaxSymbol[] binders)
{
myEnclosure = enclosure;
myNamespace = enclosure.namespace();
myBindings = bindings;
myWrap = null;
}
if (binders.length == 0) return enclosure;

static LocalEnvironment forBinders(Environment enclosure, SyntaxSymbol[] binders)
{
LocalBinding[] bindings = new LocalBinding[binders.length];
for (int i = 0; i < binders.length; i++)
{
bindings[i] = (LocalBinding) binders[i].resolve();
}
return new LocalEnvironment(enclosure, bindings);
return new LocalEnvironment(enclosure, bindings, false);
}


@Override
public Namespace namespace()
{
return myNamespace;
return myEnclosure.namespace();
}

public SyntaxWrap getWrap()
Expand Down
14 changes: 10 additions & 4 deletions runtime/src/main/java/dev/ionfusion/fusion/LocalStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class LocalStore
* Caller can (and does) mutate the array elements after constructing the
* store!
*/
LocalStore(Store enclosure, Object[] values)
private LocalStore(Store enclosure, Object[] values)
{
assert values.length > 0;
myEnclosure = enclosure;
Expand Down Expand Up @@ -68,9 +68,15 @@ public void set(int rib, int address, Object value)
//==================================================================================
// Factories

public static Store forLocals(Store enclosure, Object[] locals)

/**
* Logic for empty layers must mirror {@link LocalEnvironment#forCompilation}.
*
* @param values THE STORE ASSUMES OWNERSHIP OF THIS ARRAY.
*/
public static Store forExecution(Store enclosure, Object[] values)
{
if (locals.length == 0) return enclosure;
return new LocalStore(enclosure, locals);
if (values.length == 0) return enclosure;
return new LocalStore(enclosure, values);
}
}
Loading