use of de.mirkosertic.bytecoder.ssa.Variable in project Bytecoder by mirkosertic.
the class RedundantAssignmentOptimizer method visit.
@Override
protected void visit(ControlFlowGraph aGraph, ExpressionList aList, Expression aExpression, BytecodeLinkerContext aLinkerContext) {
// Check if a variable assignment is before the current expression
Expression theBefore = aList.predecessorOf(aExpression);
if (theBefore instanceof VariableAssignmentExpression) {
VariableAssignmentExpression theAssignment = (VariableAssignmentExpression) theBefore;
Variable theVariable = theAssignment.getVariable();
Value theValue = theAssignment.getValue();
// Check if there is only one data flow
List<Edge> theDataEdges = theVariable.outgoingEdges(DataFlowEdgeType.filter()).collect(Collectors.toList());
if (theDataEdges.size() == 1) {
List<Value> theIncomingData = aExpression.incomingDataFlows();
if (theIncomingData.contains(theVariable)) {
aExpression.replaceIncomingDataEdge(theVariable, theValue);
aList.remove(theAssignment);
aGraph.getProgram().deleteVariable(theVariable);
}
}
}
}
use of de.mirkosertic.bytecoder.ssa.Variable in project Bytecoder by mirkosertic.
the class JSSSACompilerBackend method generateCodeFor.
@Override
public JSCompileResult generateCodeFor(CompileOptions aOptions, BytecodeLinkerContext aLinkerContext, Class aEntryPointClass, String aEntryPointMethodName, BytecodeMethodSignature aEntryPointSignatue) {
BytecodeLinkedClass theExceptionRethrower = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(ExceptionRethrower.class));
theExceptionRethrower.resolveStaticMethod("registerExceptionOutcome", registerExceptionOutcomeSignature);
theExceptionRethrower.resolveStaticMethod("getLastOutcomeOrNullAndReset", getLastExceptionOutcomeSignature);
StringWriter theStrWriter = new StringWriter();
PrintWriter theWriter = new PrintWriter(theStrWriter);
theWriter.println("'use strict';");
theWriter.println();
theWriter.println("var bytecoderGlobalMemory = [];");
theWriter.println();
theWriter.println("var bytecoder = {");
theWriter.println();
theWriter.println(" logDebug : function(aValue) { ");
theWriter.println(" console.log(aValue);");
theWriter.println(" }, ");
theWriter.println();
theWriter.println(" logByteArrayAsString : function(aArray) { ");
theWriter.println(" var theResult = '';");
theWriter.println(" for (var i=0;i<aArray.data.length;i++) {");
theWriter.println(" theResult += String.fromCharCode(aArray.data[i]);");
theWriter.println(" }");
theWriter.println(" console.log(theResult);");
theWriter.println(" }, ");
theWriter.println();
theWriter.println(" newString : function(aByteArray) { ");
BytecodeObjectTypeRef theStringTypeRef = BytecodeObjectTypeRef.fromRuntimeClass(String.class);
BytecodeObjectTypeRef theArrayTypeRef = BytecodeObjectTypeRef.fromRuntimeClass(Array.class);
BytecodeMethodSignature theStringConstructorSignature = new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] { new BytecodeArrayTypeRef(BytecodePrimitiveTypeRef.BYTE, 1) });
// Construct a String
theWriter.println(" var theNewString = new " + JSWriterUtils.toClassName(theStringTypeRef) + ".Create();");
theWriter.println(" var theBytes = new " + JSWriterUtils.toClassName(theArrayTypeRef) + ".Create();");
theWriter.println(" theBytes.data = aByteArray;");
theWriter.println(" " + JSWriterUtils.toClassName(theStringTypeRef) + '.' + JSWriterUtils.toMethodName("init", theStringConstructorSignature) + "(theNewString, theBytes);");
theWriter.println(" return theNewString;");
theWriter.println(" },");
theWriter.println();
theWriter.println(" newMultiArray : function(aDimensions, aDefault) {");
theWriter.println(" var theLength = aDimensions[0];");
theWriter.println(" var theArray = bytecoder.newArray(theLength, aDefault);");
theWriter.println(" if (aDimensions.length > 1) {");
theWriter.println(" var theNewDimensions = aDimensions.slice(0);");
theWriter.println(" theNewDimensions.shift();");
theWriter.println(" for (var i=0;i<theLength;i++) {");
theWriter.println(" theArray.data[i] = bytecoder.newMultiArray(theNewDimensions, aDefault);");
theWriter.println(" }");
theWriter.println(" }");
theWriter.println(" return theArray;");
theWriter.println(" },");
theWriter.println();
theWriter.println(" newArray : function(aLength, aDefault) {");
BytecodeObjectTypeRef theArrayType = BytecodeObjectTypeRef.fromRuntimeClass(Array.class);
theWriter.println(" var theInstance = new " + JSWriterUtils.toClassName(theArrayType) + ".Create();");
theWriter.println(" theInstance.data = [];");
theWriter.println(" theInstance.data.length = aLength;");
theWriter.println(" for (var i=0;i<aLength;i++) {");
theWriter.println(" theInstance.data[i] = aDefault;");
theWriter.println(" }");
theWriter.println(" return theInstance;");
theWriter.println(" },");
theWriter.println();
theWriter.println(" dynamicType : function(aFunction) { ");
theWriter.println(" return new Proxy({}, {");
theWriter.println(" get: function(target, name) {");
theWriter.println(" return function(inst, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9) {");
theWriter.println(" return aFunction(_p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9);");
theWriter.println(" }");
theWriter.println(" }");
theWriter.println(" });");
theWriter.println(" }, ");
theWriter.println();
theWriter.println(" resolveStaticCallSiteObject: function(aWhere, aKey, aProducerFunction) {");
theWriter.println(" var resolvedCallsiteObject = aWhere.__staticCallSites[aKey];");
theWriter.println(" if (resolvedCallsiteObject == null) {");
theWriter.println(" resolvedCallsiteObject = aProducerFunction();");
theWriter.println(" aWhere.__staticCallSites[aKey] = resolvedCallsiteObject;");
theWriter.println(" }");
theWriter.println(" return resolvedCallsiteObject;");
theWriter.println(" },");
theWriter.println();
theWriter.println(" imports : [],");
theWriter.println();
theWriter.println(" stringpool : [],");
theWriter.println();
theWriter.println("};");
theWriter.println();
ConstantPool thePool = new ConstantPool();
aLinkerContext.linkedClasses().forEach(theEntry -> {
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
List<BytecodeObjectTypeRef> theInitDependencies = new ArrayList<>();
BytecodeLinkedClass theSuperClass = theLinkedClass.getSuperClass();
if (theSuperClass != null) {
theInitDependencies.add(theSuperClass.getClassName());
}
for (BytecodeLinkedClass theInterface : theLinkedClass.getImplementingTypes()) {
if (!theInitDependencies.contains(theInterface.getClassName())) {
theInitDependencies.add(theInterface.getClassName());
}
}
BytecodeResolvedMethods theMethods = theLinkedClass.resolvedMethods();
String theJSClassName = JSWriterUtils.toClassName(theEntry.edgeType().objectTypeRef());
theWriter.println("var " + theJSClassName + " = {");
// First of all, we add static fields required by the framework
theWriter.println(" __initialized : false,");
theWriter.println(" __staticCallSites : [],");
theWriter.print(" __typeId : ");
theWriter.print(theLinkedClass.getUniqueId());
theWriter.println(",");
theWriter.print(" __implementedTypes : [");
{
boolean first = true;
for (BytecodeLinkedClass theType : theLinkedClass.getImplementingTypes()) {
if (!first) {
theWriter.print(",");
}
first = false;
theWriter.print(theType.getUniqueId());
}
}
theWriter.println("],");
// then we add class specific static fields
BytecodeResolvedFields theStaticFields = theLinkedClass.resolvedFields();
theStaticFields.streamForStaticFields().forEach(aFieldEntry -> {
BytecodeTypeRef theFieldType = aFieldEntry.getValue().getTypeRef();
if (theFieldType.isPrimitive()) {
BytecodePrimitiveTypeRef thePrimitive = (BytecodePrimitiveTypeRef) theFieldType;
switch(thePrimitive) {
case BOOLEAN:
{
theWriter.print(" ");
theWriter.print(aFieldEntry.getValue().getName().stringValue());
theWriter.print(" : false, // declared in ");
theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
break;
}
default:
{
theWriter.print(" ");
theWriter.print(aFieldEntry.getValue().getName().stringValue());
theWriter.print(" : 0, // declared in ");
theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
break;
}
}
} else {
theWriter.print(" ");
theWriter.print(aFieldEntry.getValue().getName().stringValue());
theWriter.print(" : null, // declared in ");
theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
}
});
theWriter.println();
if (!theLinkedClass.getBytecodeClass().getAccessFlags().isAbstract()) {
// The Constructor function initializes all object members with null
// Only non abstract classes can be instantiated
BytecodeResolvedFields theInstanceFields = theLinkedClass.resolvedFields();
theWriter.println(" Create : function() {");
theInstanceFields.streamForInstanceFields().forEach(aFieldEntry -> {
BytecodeTypeRef theFieldType = aFieldEntry.getValue().getTypeRef();
if (theFieldType.isPrimitive()) {
BytecodePrimitiveTypeRef thePrimitive = (BytecodePrimitiveTypeRef) theFieldType;
switch(thePrimitive) {
case BOOLEAN:
{
theWriter.print(" this.");
theWriter.print(aFieldEntry.getValue().getName().stringValue());
theWriter.print(" = false; // declared in ");
theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
break;
}
default:
{
theWriter.print(" this.");
theWriter.print(aFieldEntry.getValue().getName().stringValue());
theWriter.print(" = 0; // declared in ");
theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
break;
}
}
} else {
theWriter.print(" this.");
theWriter.print(aFieldEntry.getValue().getName().stringValue());
theWriter.print(" = null; // declared in ");
theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
}
});
theWriter.println(" },");
theWriter.println();
}
if (!theLinkedClass.getBytecodeClass().getAccessFlags().isInterface()) {
theWriter.println(" instanceOf : function(aType) {");
theWriter.print(" return ");
theWriter.print(theJSClassName);
theWriter.println(".__implementedTypes.includes(aType.__typeId);");
theWriter.println(" },");
theWriter.println();
theWriter.println(" ClassgetClass : function() {");
theWriter.print(" return ");
theWriter.print(theJSClassName);
theWriter.println(";");
theWriter.println(" },");
theWriter.println();
theWriter.println(" BOOLEANdesiredAssertionStatus : function() {");
theWriter.println(" return false;");
theWriter.println(" },");
theWriter.println();
theWriter.println(" A1jlObjectgetEnumConstants : function(aClazz) {");
theWriter.println(" return aClazz.$VALUES;");
theWriter.println(" },");
}
theMethods.stream().forEach(aEntry -> {
BytecodeMethod theMethod = aEntry.getValue();
BytecodeMethodSignature theCurrentMethodSignature = theMethod.getSignature();
// If the method is provided by the runtime, we do not need to generate the implementation
if (theMethod.getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
// Do not generate code for abstract methods
if (theMethod.getAccessFlags().isAbstract()) {
return;
}
if (!(aEntry.getProvidingClass() == theLinkedClass)) {
// But include static methods, as they are inherited from the base classes
if (aEntry.getValue().getAccessFlags().isStatic() && !aEntry.getValue().isClassInitializer()) {
StringBuilder theArguments = new StringBuilder();
;
for (int i = 0; i < theCurrentMethodSignature.getArguments().length; i++) {
if (i > 0) {
theArguments.append(',');
}
theArguments.append('p');
theArguments.append(i);
}
// Static methods will just delegate to the implementation in the class
theWriter.println();
theWriter.println(" " + JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature) + " : function(" + theArguments + ") {");
if (!theCurrentMethodSignature.getReturnType().isVoid()) {
theWriter.print(" return ");
} else {
theWriter.print(" ");
}
theWriter.print(JSWriterUtils.toClassName(aEntry.getProvidingClass().getClassName()));
theWriter.print(".");
theWriter.print(JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature));
theWriter.print("(");
theWriter.print(theArguments);
theWriter.println(");");
theWriter.println(" },");
}
return;
}
aLinkerContext.getLogger().info("Compiling {}.{}", theLinkedClass.getClassName().name(), theMethod.getName().stringValue());
ProgramGenerator theGenerator = programGeneratorFactory.createFor(aLinkerContext);
Program theSSAProgram = theGenerator.generateFrom(aEntry.getProvidingClass().getBytecodeClass(), theMethod);
// Run optimizer
aOptions.getOptimizer().optimize(theSSAProgram.getControlFlowGraph(), aLinkerContext);
StringBuilder theArguments = new StringBuilder();
for (Program.Argument theArgument : theSSAProgram.getArguments()) {
if (theArguments.length() > 0) {
theArguments.append(',');
}
theArguments.append(theArgument.getVariable().getName());
}
if (theMethod.getAccessFlags().isNative()) {
if (theLinkedClass.getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
BytecodeImportedLink theLink = theLinkedClass.linkfor(theMethod);
theWriter.println();
theWriter.println(" " + JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature) + " : function(" + theArguments + ") {");
theWriter.print(" return bytecoder.imports.");
theWriter.print(theLink.getModuleName());
theWriter.print(".");
theWriter.print(theLink.getLinkName());
theWriter.print("(");
theWriter.print(theArguments);
theWriter.println(");");
theWriter.println(" },");
return;
}
theWriter.println();
theWriter.println(" " + JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature) + " : function(" + theArguments + ") {");
if (Objects.equals(theMethod.getName().stringValue(), "<clinit>")) {
for (BytecodeObjectTypeRef theRef : theSSAProgram.getStaticReferences()) {
if (!theInitDependencies.contains(theRef)) {
theInitDependencies.add(theRef);
}
}
}
if (aOptions.isDebugOutput()) {
theWriter.println(" /**");
theWriter.println(" " + theSSAProgram.getControlFlowGraph().toDOT());
theWriter.println(" */");
}
JSSSAWriter theVariablesWriter = new JSSSAWriter(aOptions, theSSAProgram, " ", theWriter, aLinkerContext, thePool);
for (Variable theVariable : theSSAProgram.globalVariables()) {
if (!theVariable.isSynthetic()) {
theVariablesWriter.print("var ");
theVariablesWriter.print(theVariable.getName());
theVariablesWriter.print(" = null;");
theVariablesWriter.print(" // type is ");
theVariablesWriter.print(theVariable.resolveType().resolve().name());
theVariablesWriter.print(" # of inits = " + theVariable.incomingDataFlows().size());
theVariablesWriter.println();
}
}
// Try to reloop it!
try {
Relooper theRelooper = new Relooper();
Relooper.Block theReloopedBlock = theRelooper.reloop(theSSAProgram.getControlFlowGraph());
theVariablesWriter.printRelooped(theReloopedBlock);
} catch (Exception e) {
System.out.println(theSSAProgram.getControlFlowGraph().toDOT());
throw new IllegalStateException("Error relooping cfg for " + theLinkedClass.getClassName().name() + '.' + theMethod.getName().stringValue(), e);
}
theWriter.println(" },");
});
theWriter.println();
theWriter.println(" classInitCheck : function() {");
theWriter.println(" if (!" + theJSClassName + ".__initialized) {");
theWriter.println(" " + theJSClassName + ".__initialized = true;");
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;");
List<BytecodeResolvedMethods.MethodEntry> theEntries = theMethods.stream().collect(Collectors.toList());
Set<String> theVisitedMethods = new HashSet<>();
for (int i = theEntries.size() - 1; i >= 0; i--) {
BytecodeResolvedMethods.MethodEntry aEntry = theEntries.get(i);
BytecodeMethod theMethod = aEntry.getValue();
String theMethodName = JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theMethod.getSignature());
if (!theMethod.getAccessFlags().isStatic() && !theMethod.getAccessFlags().isAbstract() && !theMethod.isConstructor() && !theMethod.isClassInitializer()) {
if (theVisitedMethods.add(theMethodName)) {
theWriter.print(" thePrototype.");
theWriter.print(theMethodName);
theWriter.print(" = ");
theWriter.print(JSWriterUtils.toClassName(aEntry.getProvidingClass().getClassName()));
theWriter.print(".");
theWriter.print(theMethodName);
theWriter.println(";");
}
}
}
}
for (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();
theWriter.println("};");
theWriter.println();
});
theWriter.println();
theWriter.println("bytecoder.bootstrap = function() {");
List<StringValue> theValues = thePool.stringValues();
for (int i = 0; i < theValues.size(); i++) {
StringValue theValue = theValues.get(i);
theWriter.print(" bytecoder.stringpool[");
theWriter.print(i);
theWriter.print("] = bytecoder.newString(");
theWriter.print(JSWriterUtils.toArray(theValue.getStringValue().getBytes()));
theWriter.println(");");
}
aLinkerContext.linkedClasses().forEach(aEntry -> {
if (!aEntry.targetNode().getBytecodeClass().getAccessFlags().isInterface()) {
theWriter.print(" ");
theWriter.print(JSWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
theWriter.println(".classInitCheck();");
}
});
theWriter.println("}");
theWriter.flush();
return new JSCompileResult(theStrWriter.toString());
}
use of de.mirkosertic.bytecoder.ssa.Variable in project Bytecoder by mirkosertic.
the class JSSSAWriter method print.
private void print(ResolveCallsiteObjectExpression aValue) {
print("bytecoder.resolveStaticCallSiteObject(");
print(JSWriterUtils.toClassName(aValue.getOwningClass().getThisInfo()));
print(",'");
print(aValue.getCallsiteId());
println("', function() {");
Program theProgram = aValue.getProgram();
RegionNode theBootstrapCode = aValue.getBootstrapMethod();
JSSSAWriter theNested = withDeeperIndent();
for (Variable theVariable : theProgram.globalVariables()) {
theNested.print("var ");
theNested.print(theVariable.getName());
theNested.println(" = null;");
}
theNested.writeExpressions(theBootstrapCode.getExpressions());
print("})");
}
use of de.mirkosertic.bytecoder.ssa.Variable in project Bytecoder by mirkosertic.
the class OpenCLWriter method writeExpressions.
private void writeExpressions(ExpressionList aList) {
for (Expression theExpression : aList.toList()) {
if (options.isDebugOutput()) {
String theComment = theExpression.getComment();
if (theComment != null && !theComment.isEmpty()) {
print("// ");
println(theComment);
}
}
if (theExpression instanceof VariableAssignmentExpression) {
VariableAssignmentExpression theInit = (VariableAssignmentExpression) theExpression;
Variable theVariable = theInit.getVariable();
Value theValue = theInit.getValue();
if (theVariable.resolveType().isObject() && theValue instanceof InvocationExpression) {
print(toType(theVariable.resolveType(), false));
print(" ");
print(theVariable.getName());
print("_temp = ");
printValue(theValue);
println(";");
print(theVariable.getName());
print(" = &");
print(theVariable.getName());
println("_temp;");
} else {
print(theVariable.getName());
print(" = ");
printValue(theValue);
println(";");
}
} else if (theExpression instanceof ArrayStoreExpression) {
ArrayStoreExpression theStore = (ArrayStoreExpression) theExpression;
List<Value> theIncomingData = theStore.incomingDataFlows();
Value theArray = theIncomingData.get(0);
Value theIndex = theIncomingData.get(1);
Value theValue = theIncomingData.get(2);
printValue(theArray);
print("[");
printValue(theIndex);
print("] = ");
printValue(theValue);
println(";");
} else if (theExpression instanceof IFExpression) {
IFExpression theE = (IFExpression) theExpression;
print("if ");
printValue(theE.incomingDataFlows().get(0));
println(" {");
withDeeperIndent().writeExpressions(theE.getExpressions());
println("}");
} else if (theExpression instanceof BreakExpression) {
BreakExpression theBreak = (BreakExpression) theExpression;
if (theBreak.isSetLabelRequired()) {
print("$__label__ = ");
print(theBreak.jumpTarget().getAddress());
println(";");
}
if (!theBreak.isSilent()) {
print("goto $");
print(theBreak.blockToBreak().name());
println("_next;");
}
} else if (theExpression instanceof ContinueExpression) {
ContinueExpression theContinue = (ContinueExpression) theExpression;
print("$__label__ = ");
print(theContinue.jumpTarget().getAddress());
println(";");
print("goto $");
print(theContinue.labelToReturnTo().name());
println(";");
} else if (theExpression instanceof ReturnExpression) {
println("return;");
} else if (theExpression instanceof PutFieldExpression) {
PutFieldExpression thePutField = (PutFieldExpression) theExpression;
List<Value> theIncomingData = thePutField.incomingDataFlows();
Value theTarget = theIncomingData.get(0);
BytecodeFieldRefConstant theField = thePutField.getField();
Value thevalue = theIncomingData.get(1);
printValue(theTarget);
printInstanceFieldReference(theField);
print(" = ");
printValue(thevalue);
println(";");
} else if (theExpression instanceof ReturnValueExpression) {
ReturnValueExpression theReturn = (ReturnValueExpression) theExpression;
List<Value> theIncomingData = theReturn.incomingDataFlows();
print("return ");
printValue(theIncomingData.get(0));
println(";");
} else {
throw new IllegalArgumentException("Not supported. " + theExpression);
}
}
}
use of de.mirkosertic.bytecoder.ssa.Variable in project Bytecoder by mirkosertic.
the class OpenCLWriter method printGetFieldValue.
private void printGetFieldValue(GetFieldExpression aValue) {
BytecodeLinkedClass theLinkedClass = linkerContext.resolveClass(BytecodeObjectTypeRef.fromUtf8Constant(aValue.getField().getClassIndex().getClassConstant().getConstant()));
if (theLinkedClass == kernelClass) {
print(aValue.getField().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue());
} else {
Value theValue = aValue.incomingDataFlows().get(0);
if (theValue instanceof Variable && ((Variable) theValue).isSynthetic()) {
print(aValue.getField().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue());
} else {
printValue(theValue);
printInstanceFieldReference(aValue.getField());
}
}
}
Aggregations