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
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,24 @@ public boolean isFinal() {
return inspection.get().isFinal();
}

// @IgnoreModifications (road §050): idempotent memo state, disclaimed -- the VariableImpl.cachedHash precedent.
// The name holds the method's full signature, and the prepwork analysis keys every statement's variable data by it
// (VariableDataImpl.vicByFqn): built anew on every call, each statement kept its own copy, N parameters times N
// statements copies of a name that grows with N. Constructors of 150 parameters on a closed-core corpus filled a
// 24 GB heap while parsing. Interned, as FieldReferenceImpl's name is (CodeLaser/maddi-mod#16). Kept only once the
// method is committed: while it is built its signature can still gain parameters.
@IgnoreModifications
private volatile String fullyQualifiedName;

@Override
public String fullyQualifiedName() {
return methodInfo.fullyQualifiedName() + ":" + index + ":" + simpleName();
String fqn = fullyQualifiedName;
if (fqn != null) return fqn;
fqn = methodInfo.fullyQualifiedName() + ":" + index + ":" + simpleName();
if (!methodInfo.hasBeenInspected()) return fqn;
fqn = fqn.intern();
fullyQualifiedName = fqn;
return fqn;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.codelaser.maddi.cst.impl.info;

import io.codelaser.maddi.cst.api.element.CompilationUnit;
import io.codelaser.maddi.cst.api.info.MethodInfo;
import io.codelaser.maddi.cst.api.info.ParameterInfo;
import io.codelaser.maddi.cst.api.info.TypeInfo;
import io.codelaser.maddi.cst.api.runtime.Runtime;
import io.codelaser.maddi.cst.impl.runtime.RuntimeImpl;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;

/**
* A parameter's fully qualified name holds its method's full signature. The prepwork analysis keys every statement's
* variable data by it (VariableDataImpl.vicByFqn), so a name built anew on every call was stored once per statement:
* N parameters times N statements copies of a name that grows with N. On a closed-core corpus with constructors of 150
* parameters a 24 GB heap ran out while parsing. The name is built once the method is committed, and shared.
*/
public class TestParameterFullyQualifiedName {

@DisplayName("a parameter of a committed method returns one shared name, not a new copy per call")
@Test
public void theNameOfAParameterIsShared() {
Runtime runtime = new RuntimeImpl();
CompilationUnit cu = runtime.newCompilationUnitBuilder().setPackageName("com.foo").build();
TypeInfo ti = runtime.newTypeInfo(cu, "Wide");
MethodInfo m = runtime.newConstructor(ti);
for (int i = 0; i < 150; i++) {
m.builder().addParameter("p" + i, runtime.stringParameterizedType()).builder().commit();
}
m.builder().commitParameters().commit();
ParameterInfo p = m.parameters().get(149);
String first = p.fullyQualifiedName();
assertEquals(m.fullyQualifiedName() + ":149:p149", first,
"the name of parameter 149 (actual) against the method's name, index and name (expected)");
assertSame(first, p.fullyQualifiedName(),
"the name returned by the second call (actual) against the very string the first call returned (expected)");
}

@DisplayName("a name asked for while the method is still being built is not kept")
@Test
public void aNameAskedForBeforeTheMethodIsCommittedIsNotKept() {
Runtime runtime = new RuntimeImpl();
CompilationUnit cu = runtime.newCompilationUnitBuilder().setPackageName("com.foo").build();
TypeInfo ti = runtime.newTypeInfo(cu, "Growing");
MethodInfo m = runtime.newMethod(ti, "run", runtime.methodTypeMethod());
ParameterInfo first = m.builder().addParameter("a", runtime.stringParameterizedType());
first.builder().commit();
String early = first.fullyQualifiedName();
m.builder().addParameter("b", runtime.intParameterizedType()).builder().commit();
m.builder().commitParameters().commit();
assertEquals(m.fullyQualifiedName() + ":0:a", first.fullyQualifiedName(),
"the name after the method is committed (actual) against one that holds both parameters (expected); "
+ "asked for while building it was '" + early + "'");
}
}
Loading