Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move object method bodies into a separate class when original class is too large #41398

Closed
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public class ErrorValue extends BError implements RefValue {
private final Object details;

private static final String GENERATE_OBJECT_CLASS_PREFIX = "$value$";
private static final String SPLIT_CLASS_SUFFIX_REGEX = "\\$split\\$\\d";
private static final String GENERATE_PKG_INIT = "___init_";
private static final String GENERATE_PKG_START = "___start_";
private static final String GENERATE_PKG_STOP = "___stop_";
Expand Down Expand Up @@ -441,7 +442,7 @@ private Optional<StackTraceElement> filterStackTraceElement(StackTraceElement st
}

private String cleanupClassName(String className) {
return className.replace(GENERATE_OBJECT_CLASS_PREFIX, "");
return className.replace(GENERATE_OBJECT_CLASS_PREFIX, "").replaceAll(SPLIT_CLASS_SUFFIX_REGEX, "");
}

private boolean isCompilerAddedName(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ public static String getMethodDesc(List<BType> paramTypes, BType retType, BType
generateReturnType(retType);
}

public static String getMethodDesc(List<BType> paramTypes, BType retType, String attachedTypeClassName) {
return INITIAL_METHOD_DESC + "L" + attachedTypeClassName + ";" + populateMethodDesc(paramTypes) +
generateReturnType(retType);
}

public static String populateMethodDesc(List<BType> paramTypes) {
StringBuilder descBuilder = new StringBuilder();
for (BType type : paramTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ public class JvmConstants {

// code generation related constants.
public static final String MODULE_INIT_CLASS_NAME = "$_init";
public static final String OBJECT_SELF_INSTANCE = "self";
public static final String UNION_TYPE_CONSTANT_CLASS_NAME = "constants/$_union_type_constants";
public static final String ERROR_TYPE_CONSTANT_CLASS_NAME = "constants/$_error_type_constants";
public static final String TUPLE_TYPE_CONSTANT_CLASS_NAME = "constants/$_tuple_type_constants";
Expand Down Expand Up @@ -380,6 +381,7 @@ public class JvmConstants {
public static final String START_OF_HEADING_WITH_SEMICOLON = ":\u0001";
public static final String CREATE_INTEROP_ERROR_METHOD = "createInteropError";
public static final String LAMBDA_PREFIX = "$lambda$";
public static final String SPLIT_CLASS_SUFFIX = "$split$";
public static final String POPULATE_METHOD_PREFIX = "$populate";
public static final String ADD_METHOD = "add";
public static final String TEST_EXECUTION_STATE = "__gH7W16nQmp0TestExecState__";
Expand Down Expand Up @@ -446,6 +448,7 @@ public class JvmConstants {
public static final int MAX_CALLS_PER_CLIENT_METHOD = 100;
public static final int MAX_CONSTANTS_PER_METHOD = 100;
public static final int MAX_CALLS_PER_FUNCTION_CALL_METHOD = 100;
public static final int MAX_METHOD_COUNT_PER_BALLERINA_OBJECT = 100;
/*
MAX_STRINGS_PER_METHOD is calculated as below.
No of instructions required for create ballerina string constant object = 12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAP_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MATH_UTILS;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT_SELF_INSTANCE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT_TYPE_IMPL;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.REG_EXP_FACTORY;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SHORT_VALUE;
Expand Down Expand Up @@ -432,7 +433,7 @@ public void generateVarLoad(MethodVisitor mv, BIRNode.BIRVariableDcl varDcl, int

switch (varDcl.kind) {
case SELF:
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, this.indexMap.get(OBJECT_SELF_INSTANCE));
return;
case CONSTANT:
case GLOBAL:
Expand Down Expand Up @@ -1517,7 +1518,7 @@ void generateObjectStoreIns(BIRNonTerminator.FieldAccess objectStoreIns) {
this.mv.visitTypeInsn(CHECKCAST, className);
visitKeyValueExpressions(objectStoreIns);
// invoke setOnInitialization() method
this.mv.visitMethodInsn(INVOKESPECIAL, className, "setOnInitialization",
this.mv.visitMethodInsn(INVOKEVIRTUAL, className, "setOnInitialization",
SET_ON_INIT, false);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ private static void generateLockForVariable(ClassWriter cw) {
private static void generateStaticInitializer(ClassWriter cw, String className, BIRPackage birPackage,
boolean isInitClass, boolean serviceEPAvailable,
AsyncDataCollector asyncDataCollector,
JvmConstantsGen jvmConstantsGen, boolean isTestablePackage) {
JvmConstantsGen jvmConstantsGen) {
if (!isInitClass && asyncDataCollector.getStrandMetadata().isEmpty()) {
return;
}
Expand Down Expand Up @@ -432,7 +432,7 @@ private void generateModuleClasses(BIRPackage module, Map<String, byte[]> jarEnt
}
JvmCodeGenUtil.visitStrandMetadataFields(cw, asyncDataCollector.getStrandMetadata());
generateStaticInitializer(cw, moduleClass, module, isInitClass, serviceEPAvailable,
asyncDataCollector, jvmConstantsGen, isTestable);
asyncDataCollector, jvmConstantsGen);
cw.visitEnd();

byte[] bytes = getBytes(cw, module);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1274,7 +1274,6 @@ static String getStrandMetadataVarName(String typeName, String parentFunction) {
}

private void loadFpReturnType(BIROperand lhsOp) {

BType futureType = JvmCodeGenUtil.getImpliedType(lhsOp.variableDcl.type);
BType returnType = symbolTable.anyType;
if (futureType.tag == TypeTags.FUTURE) {
Expand All @@ -1289,12 +1288,10 @@ private int getJVMIndexOfVarRef(BIRNode.BIRVariableDcl varDcl) {
}

private void loadVar(BIRNode.BIRVariableDcl varDcl) {

jvmInstructionGen.generateVarLoad(this.mv, varDcl, this.getJVMIndexOfVarRef(varDcl));
}

private void storeToVar(BIRNode.BIRVariableDcl varDcl) {

jvmInstructionGen.generateVarStore(this.mv, varDcl, this.getJVMIndexOfVarRef(varDcl));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LOCK_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAP_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAP_VALUE_IMPL;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAX_METHOD_COUNT_PER_BALLERINA_OBJECT;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.POPULATE_INITIAL_VALUES_METHOD;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RECORD_INIT_WRAPPER_NAME;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SPLIT_CLASS_SUFFIX;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND_CLASS;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TYPEDESC_CLASS_PREFIX;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TYPEDESC_VALUE;
Expand Down Expand Up @@ -226,9 +228,8 @@ void generateValueClasses(Map<String, byte[]> jarEntries, JvmConstantsGen jvmCon
if (optionalTypeDef.type.tag == TypeTags.OBJECT &&
Symbols.isFlagOn(optionalTypeDef.type.tsymbol.flags, Flags.CLASS)) {
BObjectType objectType = (BObjectType) optionalTypeDef.type;
byte[] bytes = this.createObjectValueClass(objectType, className, optionalTypeDef, jvmConstantsGen
, asyncDataCollector);
jarEntries.put(className + ".class", bytes);
this.createObjectValueClasses(objectType, className, optionalTypeDef, jvmConstantsGen
, asyncDataCollector, jarEntries);
} else if (bType.tag == TypeTags.RECORD) {
BRecordType recordType = (BRecordType) bType;
byte[] bytes = this.createRecordValueClass(recordType, className, optionalTypeDef, jvmConstantsGen
Expand Down Expand Up @@ -591,8 +592,9 @@ private void createRecordPopulateInitialValuesMethod(ClassWriter cw, String clas
mv.visitEnd();
}

private byte[] createObjectValueClass(BObjectType objectType, String className, BIRNode.BIRTypeDefinition typeDef,
JvmConstantsGen jvmConstantsGen, AsyncDataCollector asyncDataCollector) {
private void createObjectValueClasses(BObjectType objectType, String className, BIRNode.BIRTypeDefinition typeDef,
JvmConstantsGen jvmConstantsGen, AsyncDataCollector asyncDataCollector,
Map<String, byte[]> jarEntries) {
ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES);
cw.visitSource(typeDef.pos.lineRange().fileName(), null);

Expand All @@ -607,8 +609,13 @@ private byte[] createObjectValueClass(BObjectType objectType, String className,

List<BIRNode.BIRFunction> attachedFuncs = typeDef.attachedFuncs;
if (attachedFuncs != null) {
this.createObjectMethods(cw, attachedFuncs, className, objectType, jvmTypeGen, jvmCastGen,
jvmConstantsGen, asyncDataCollector);
if (attachedFuncs.size() > MAX_METHOD_COUNT_PER_BALLERINA_OBJECT) {
this.createObjectMethodsWithSplitClasses(cw, attachedFuncs, className, objectType, jvmTypeGen,
jvmCastGen, jvmConstantsGen, asyncDataCollector, typeDef, jarEntries);
} else {
this.createObjectMethods(cw, attachedFuncs, className, objectType, jvmTypeGen, jvmCastGen,
jvmConstantsGen, asyncDataCollector);
}
}

this.createObjectInit(cw, fields, className);
Expand All @@ -619,9 +626,8 @@ private byte[] createObjectValueClass(BObjectType objectType, String className,
this.createLambdas(cw, asyncDataCollector, lambdaGen, className);
JvmCodeGenUtil.visitStrandMetadataFields(cw, asyncDataCollector.getStrandMetadata());
this.generateStaticInitializer(cw, className, module.packageID, asyncDataCollector);

cw.visitEnd();
return jvmPackageGen.getBytes(cw, typeDef);
jarEntries.put(className + ".class", jvmPackageGen.getBytes(cw, typeDef));
}

private void createObjectFields(ClassWriter cw, Map<String, BField> fields) {
Expand All @@ -639,16 +645,66 @@ private void createObjectFields(ClassWriter cw, Map<String, BField> fields) {
}
}

private void createObjectMethods(ClassWriter cw, List<BIRNode.BIRFunction> attachedFuncs, String moduleClassName,
private void createObjectMethods(ClassWriter cw, List<BIRFunction> attachedFuncs, String moduleClassName,
BObjectType currentObjectType, JvmTypeGen jvmTypeGen, JvmCastGen jvmCastGen,
JvmConstantsGen jvmConstantsGen, AsyncDataCollector asyncDataCollector) {

for (BIRNode.BIRFunction func : attachedFuncs) {
if (func == null) {
continue;
}
methodGen.generateMethod(func, cw, module, currentObjectType, moduleClassName,
jvmTypeGen, jvmCastGen, jvmConstantsGen, asyncDataCollector);
methodGen.generateMethod(func, cw, module, currentObjectType, moduleClassName, jvmTypeGen, jvmCastGen,
jvmConstantsGen, asyncDataCollector);
}
}

private void createObjectMethodsWithSplitClasses(ClassWriter cw, List<BIRFunction> attachedFuncs,
String moduleClassName, BObjectType currentObjectType,
JvmTypeGen jvmTypeGen, JvmCastGen jvmCastGen,
JvmConstantsGen jvmConstantsGen,
AsyncDataCollector asyncDataCollector,
BIRNode.BIRTypeDefinition typeDef,
Map<String, byte[]> jarEntries) {

int splitClassNum = 1;
ClassWriter splitCW = new BallerinaClassWriter(COMPUTE_FRAMES);
splitCW.visitSource(typeDef.pos.lineRange().fileName(), null);
String splitClassName = moduleClassName + SPLIT_CLASS_SUFFIX + splitClassNum;
splitCW.visit(V17, ACC_PUBLIC + ACC_SUPER, splitClassName, null, OBJECT, null);
JvmCodeGenUtil.generateDefaultConstructor(splitCW, OBJECT);
int methodCountPerSplitClass = 0;

for (BIRNode.BIRFunction func : attachedFuncs) {
if (func == null) {
continue;
}
if (func.name.value.contains("$init$")) {
methodGen.generateMethod(func, cw, module, currentObjectType, moduleClassName,
jvmTypeGen, jvmCastGen, jvmConstantsGen, asyncDataCollector);
continue;
}
methodGen.genJMethodWithBObjectMethodCall(func, cw, module, jvmTypeGen, jvmCastGen, jvmConstantsGen,
moduleClassName, asyncDataCollector, splitClassName);
methodGen.genJMethodForBFunc(func, splitCW, module, jvmTypeGen, jvmCastGen, jvmConstantsGen,
moduleClassName, currentObjectType, asyncDataCollector, true);
methodCountPerSplitClass++;
if (methodCountPerSplitClass == MAX_METHOD_COUNT_PER_BALLERINA_OBJECT) {
splitCW.visitEnd();
byte[] splitBytes = jvmPackageGen.getBytes(splitCW, typeDef);
jarEntries.put(splitClassName + ".class", splitBytes);
splitClassNum++;
splitCW = new BallerinaClassWriter(COMPUTE_FRAMES);
splitCW.visitSource(typeDef.pos.lineRange().fileName(), null);
splitClassName = moduleClassName + SPLIT_CLASS_SUFFIX + splitClassNum;
splitCW.visit(V17, ACC_PUBLIC + ACC_SUPER, splitClassName, null, OBJECT, null);
JvmCodeGenUtil.generateDefaultConstructor(splitCW, OBJECT);
methodCountPerSplitClass = 0;
}
}
if (methodCountPerSplitClass != 0) {
splitCW.visitEnd();
byte[] splitBytes = jvmPackageGen.getBytes(splitCW, typeDef);
jarEntries.put(splitClassName + ".class", splitBytes);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static void genJMethodForBExternalFunc(BIRFunction birFunc, ClassWriter c
jvmCastGen, jvmConstantsGen, lambdaGenMetadata, types);
} else {
methodGen.genJMethodForBFunc(birFunc, cw, birModule, jvmTypeGen, jvmCastGen, jvmConstantsGen,
moduleClassName, attachedType, lambdaGenMetadata);
moduleClassName, attachedType, lambdaGenMetadata, false);
}
}

Expand Down
Loading