Skip to content

Commit

Permalink
#87 Fix static class initialization order
Browse files Browse the repository at this point in the history
  • Loading branch information
mirkosertic committed Jan 21, 2019
1 parent c9f0a78 commit 7a870fe
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 105 deletions.
Expand Up @@ -43,10 +43,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -331,21 +329,6 @@ public JSCompileResult generateCodeFor(final CompileOptions aOptions, final Byte
aLinkerContext.linkedClasses().forEach(theEntry -> {

final BytecodeLinkedClass theLinkedClass = theEntry.targetNode();

// Here we collect everything that is required for class initialization
// this includes the super class, all implementing interfaces and also static
// dependencies of the class initialization code
final List<BytecodeObjectTypeRef> theInitDependencies = new ArrayList<>();
final BytecodeLinkedClass theSuperClass = theLinkedClass.getSuperClass();
if (null != theSuperClass) {
theInitDependencies.add(theSuperClass.getClassName());
}
for (final BytecodeLinkedClass theInterface : theLinkedClass.getImplementingTypes()) {
if (!theInitDependencies.contains(theInterface.getClassName())) {
theInitDependencies.add(theInterface.getClassName());
}
}

final BytecodeResolvedMethods theMethods = theLinkedClass.resolvedMethods();

final String theJSClassName = JSWriterUtils.toClassName(theEntry.edgeType().objectTypeRef());
Expand Down Expand Up @@ -402,6 +385,7 @@ public JSCompileResult generateCodeFor(final CompileOptions aOptions, final Byte
// Only non abstract classes can be instantiated
final BytecodeResolvedFields theInstanceFields = theLinkedClass.resolvedFields();
theWriter.println(" Create : function() {");
theWriter.println(" " + theJSClassName + ".init();");
theInstanceFields.streamForInstanceFields().forEach(
aFieldEntry -> {
if (aFieldEntry.getProvidingClass() == theLinkedClass) {
Expand Down Expand Up @@ -556,14 +540,6 @@ public JSCompileResult generateCodeFor(final CompileOptions aOptions, final Byte
theWriter.println(" " + JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature) + " : function(" + theArguments
+ ") {");

// if (Objects.equals(theMethod.getName().stringValue(), "<clinit>")) {
for (final BytecodeObjectTypeRef theRef : theSSAProgram.getStaticReferences()) {
if (!theInitDependencies.contains(theRef)) {
theInitDependencies.add(theRef);
}
}
// }

if (aOptions.isDebugOutput()) {
theWriter.println(" /**");
theWriter.println(" " + theSSAProgram.getControlFlowGraph().toDOT());
Expand Down Expand Up @@ -600,18 +576,35 @@ public JSCompileResult generateCodeFor(final CompileOptions aOptions, final Byte
theWriter.println(" },");
});


theWriter.println();
theWriter.println(" classInitCheck : function() {");
theWriter.println(" init : function() {");
theWriter.println(" if (!" + theJSClassName + ".__initialized) {");
theWriter.println(" " + theJSClassName + ".__initialized = true;");

if (!theLinkedClass.getClassName().name().equals(Object.class.getName())) {
final BytecodeLinkedClass theSuper = theLinkedClass.getSuperClass();
final String theSuperJSName = JSWriterUtils.toClassName(theSuper.getClassName());
theWriter.println(" " + theSuperJSName + ".init();");
}

if (theLinkedClass.hasClassInitializer()) {
theWriter.println(" " + theJSClassName + ".VOIDclinit();");
}

theWriter.println(" }");
theWriter.println(" return " + theJSClassName + ";");
theWriter.println(" },");
theWriter.println();

theWriter.println();
theWriter.println(" link : function() {");

if (!theLinkedClass.getBytecodeClass().getAccessFlags().isAbstract()) {
// Now we have to setup the prototype
// Only in case this class can be instantiated of course
theWriter.println(" var thePrototype = " + theJSClassName + ".Create.prototype;");
theWriter.println(" thePrototype.instanceOf = " + theJSClassName + ".instanceOf;");
theWriter.println(" thePrototype.ClassgetClass = " + theJSClassName + ".ClassgetClass;");
theWriter.println(" var thePrototype = " + theJSClassName + ".Create.prototype;");
theWriter.println(" thePrototype.instanceOf = " + theJSClassName + ".instanceOf;");
theWriter.println(" thePrototype.ClassgetClass = " + theJSClassName + ".ClassgetClass;");

final List<BytecodeResolvedMethods.MethodEntry> theEntries = theMethods.stream().collect(Collectors.toList());
final Set<String> theVisitedMethods = new HashSet<>();
Expand All @@ -627,7 +620,7 @@ public JSCompileResult generateCodeFor(final CompileOptions aOptions, final Byte
!theMethod.isClassInitializer()) {

if (theVisitedMethods.add(theMethodName)) {
theWriter.print(" thePrototype.");
theWriter.print(" thePrototype.");
theWriter.print(theMethodName);
theWriter.print(" = ");
theWriter.print(JSWriterUtils.toClassName(aEntry.getProvidingClass().getClassName()));
Expand All @@ -639,18 +632,6 @@ public JSCompileResult generateCodeFor(final CompileOptions aOptions, final Byte
}
}

for (final BytecodeObjectTypeRef theRef : theInitDependencies) {
if (!Objects.equals(theRef, theEntry.edgeType().objectTypeRef())) {
theWriter.print(" ");
theWriter.print(JSWriterUtils.toClassName(theRef));
theWriter.println(".classInitCheck();");
}
}
if (theLinkedClass.hasClassInitializer()) {
theWriter.println(" " + theJSClassName + ".VOIDclinit();");
}
theWriter.println(" }");

theWriter.println(" },");
theWriter.println();

Expand All @@ -674,7 +655,7 @@ public JSCompileResult generateCodeFor(final CompileOptions aOptions, final Byte
if (!aEntry.targetNode().getBytecodeClass().getAccessFlags().isInterface()) {
theWriter.print(" ");
theWriter.print(JSWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
theWriter.println(".classInitCheck();");
theWriter.println(".link();");
}
final BytecodeResolvedMethods theMethods = aEntry.targetNode().resolvedMethods();
theMethods.stream().forEach(eMethod -> {
Expand Down
Expand Up @@ -385,6 +385,7 @@ private void print(final NewMultiArrayExpression aValue) {

private void print(final ClassReferenceValue aValue) {
print(JSWriterUtils.toClassName(aValue.getType()));
print(".init()");
}

private void print(final InstanceOfExpression aValue) {
Expand Down Expand Up @@ -751,7 +752,7 @@ private void print(final InvokeStaticMethodExpression aValue) {
} else {

print(JSWriterUtils.toClassName(aValue.getClassName()));
print(".");
print(".init().");
print(JSWriterUtils.toMethodName(theMethodName, theSignature));
print("(");

Expand Down Expand Up @@ -974,7 +975,7 @@ private void printStaticFieldReference(final BytecodeFieldRefConstant aField) {
final BytecodeResolvedFields theFields = theLinkedClass.resolvedFields();
final BytecodeResolvedFields.FieldEntry theField = theFields.fieldByName(aField.getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue());
print(JSWriterUtils.toClassName(theField.getProvidingClass().getClassName()));
print(".");
print(".init().");
print(aField.getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue());
}

Expand Down

0 comments on commit 7a870fe

Please sign in to comment.