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

Improve runtime anonymous type resolution #29792

Merged
merged 17 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8300bff
Add type hash based runtime type resolver
grainier Apr 2, 2021
d0eeec5
Merge branch 'master' of github.com:ballerina-platform/ballerina-lang…
grainier Apr 2, 2021
bfd22ce
Fix class doc comment
grainier Apr 2, 2021
c397964
Improve type hash visitor and add missing type visits
grainier Apr 2, 2021
61f2901
Improve anon type resolution on default package
grainier Apr 2, 2021
39479a2
Merge branch 'master' of github.com:ballerina-platform/ballerina-lang…
grainier Apr 2, 2021
fc37869
Fix runtime type param loading issue
grainier Apr 4, 2021
6ba89a5
Merge branch 'master' of github.com:ballerina-platform/ballerina-lang…
grainier Apr 4, 2021
9a611ab
Restrict usage of getAnonType method to inter-module type loading
grainier Apr 8, 2021
74ece3f
Merge branch 'master' of github.com:ballerina-platform/ballerina-lang…
grainier Apr 8, 2021
0afb1cf
Update compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/c…
grainier Apr 9, 2021
f28a023
Update compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/c…
grainier Apr 9, 2021
1878f20
Include type id set hash error type and object type hashes
grainier Apr 15, 2021
2b99063
Merge branch 'master' of github.com:ballerina-platform/ballerina-lang…
grainier Apr 15, 2021
c747628
Merge remote-tracking branch 'origin/fix-28262-v2' into fix-28262-v2
grainier Apr 15, 2021
3da69b3
Use ANONYMOUS flag to check whether a type is an anon type
grainier Apr 15, 2021
fa7bb1c
Merge branch 'master' of github.com:ballerina-platform/ballerina-lang…
grainier Apr 15, 2021
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 @@ -17,6 +17,7 @@
*/
package io.ballerina.runtime.internal.values;

import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.values.BError;
import io.ballerina.runtime.api.values.BObject;
import io.ballerina.runtime.api.values.BString;
Expand Down Expand Up @@ -86,4 +87,7 @@ public abstract BObject createObjectValue(String objectTypeName, Scheduler sched

public abstract BError createErrorValue(String errorTypeName, BString message, BError cause, Object details)
throws BError;

public abstract Type getAnonType(int typeHash, String typeShape) throws BError;

}
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ public class JvmConstants {
public static final String CREATE_RECORD_VALUE = "createRecordValue";
public static final String CREATE_OBJECT_VALUE = "createObjectValue";
public static final String CREATE_ERROR_VALUE = "createErrorValue";
public static final String GET_ANON_TYPE = "getAnonType";

// strand data related constants
public static final String STRAND = "strand";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,13 +455,14 @@ private void generateModuleClasses(BIRPackage module, Map<String, byte[]> jarEnt
ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES);
AsyncDataCollector asyncDataCollector = new AsyncDataCollector(moduleClass);
boolean isInitClass = Objects.equals(moduleClass, moduleInitClass);
JvmTypeGen jvmTypeGen = new JvmTypeGen(stringConstantsGen);
JvmTypeGen jvmTypeGen = new JvmTypeGen(stringConstantsGen, module.packageID);
JvmCastGen jvmCastGen = new JvmCastGen(symbolTable, jvmTypeGen);
LambdaGen lambdaGen = new LambdaGen(this, jvmCastGen);
if (isInitClass) {
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, moduleClass, null, VALUE_CREATOR, null);
JvmCodeGenUtil.generateDefaultConstructor(cw, VALUE_CREATOR);
jvmTypeGen.generateUserDefinedTypeFields(cw, module.typeDefs);
jvmTypeGen.generateGetAnonTypeMethod(cw, module.typeDefs, moduleInitClass);
jvmTypeGen.generateValueCreatorMethods(cw, module.typeDefs, module.packageID, moduleInitClass,
symbolTable, asyncDataCollector);
// populate global variable to class name mapping and generate them
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap;
import org.wso2.ballerinalang.compiler.bir.codegen.internal.ScheduleFunctionInfo;
import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRTypeDefinition;
import org.wso2.ballerinalang.compiler.parser.BLangAnonymousModelHelper;
import org.wso2.ballerinalang.compiler.semantics.analyzer.IsAnydataUniqueVisitor;
import org.wso2.ballerinalang.compiler.semantics.analyzer.IsPureTypeUniqueVisitor;
import org.wso2.ballerinalang.compiler.semantics.analyzer.TypeHashVisitor;
import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BAttachedFunction;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BObjectTypeSymbol;
Expand Down Expand Up @@ -66,6 +68,7 @@
import org.wso2.ballerinalang.util.Flags;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -91,6 +94,7 @@
import static org.objectweb.asm.Opcodes.IFEQ;
import static org.objectweb.asm.Opcodes.IFNE;
import static org.objectweb.asm.Opcodes.IFNONNULL;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INSTANCEOF;
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
Expand Down Expand Up @@ -133,6 +137,7 @@
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.FUNCTION_TYPE_IMPL;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.FUTURE_TYPE_IMPL;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.FUTURE_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.GET_ANON_TYPE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_TYPE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.INTEGER_TYPE;
Expand Down Expand Up @@ -195,6 +200,7 @@
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.XML_TYPE_IMPL;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.XML_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmValueGen.NAME_HASH_COMPARATOR;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmValueGen.TYPE_HASH_COMPARATOR;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmValueGen.createDefaultCase;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmValueGen.getTypeDescClassName;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmValueGen.getTypeValueClassName;
Expand All @@ -209,11 +215,15 @@ public class JvmTypeGen {
private final IsPureTypeUniqueVisitor isPureTypeUniqueVisitor;
private final IsAnydataUniqueVisitor isAnydataUniqueVisitor;
private final JvmBStringConstantsGen stringConstantsGen;
private final TypeHashVisitor typeHashVisitor;
private final PackageID packageID;

public JvmTypeGen(JvmBStringConstantsGen stringConstantsGen) {
public JvmTypeGen(JvmBStringConstantsGen stringConstantsGen, PackageID packageID) {
this.stringConstantsGen = stringConstantsGen;
this.packageID = packageID;
isPureTypeUniqueVisitor = new IsPureTypeUniqueVisitor();
isAnydataUniqueVisitor = new IsAnydataUniqueVisitor();
typeHashVisitor = new TypeHashVisitor();
}

/**
Expand Down Expand Up @@ -501,6 +511,75 @@ static List<Label> createLabelsForEqualCheck(MethodVisitor mv, int nameRegIndex,
return targetLabels;
}

// -------------------------------------------------------
// getAnonType() generation methods
// -------------------------------------------------------

void generateGetAnonTypeMethod(ClassWriter cw, List<BIRTypeDefinition> typeDefinitions, String typeOwnerClass) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, GET_ANON_TYPE,
String.format("(IL%s;)L%s;", STRING_VALUE, TYPE), null, null);
mv.visitCode();

int hashParamRegIndex = 1;
int shapeParamRegIndex = 2;
Label defaultCaseLabel = new Label();

// filter anon types and sorts them before generating switch case.
Set<BIRTypeDefinition> typeDefSet = new TreeSet<>(TYPE_HASH_COMPARATOR);
for (BIRTypeDefinition t : typeDefinitions) {
if (t.internalName.value.contains(BLangAnonymousModelHelper.ANON_PREFIX)
|| Symbols.isFlagOn(t.type.flags, Flags.ANONYMOUS)) {
typeDefSet.add(t);
}
}

Map<String, Label> labels = createLabelsForAnonTypeHashSwitch(mv, hashParamRegIndex,
typeDefSet, defaultCaseLabel);

for (Map.Entry<String, Label> labelEntry : labels.entrySet()) {
String fieldName = labelEntry.getKey();
Label targetLabel = labelEntry.getValue();
mv.visitLabel(targetLabel);
mv.visitFieldInsn(GETSTATIC, typeOwnerClass, fieldName, String.format("L%s;", TYPE));
mv.visitInsn(ARETURN);
}

createDefaultCase(mv, defaultCaseLabel, shapeParamRegIndex, "No such type: ");
mv.visitMaxs(typeDefSet.size() + 10, typeDefSet.size() + 10);
mv.visitEnd();
}

private Map<String, Label> createLabelsForAnonTypeHashSwitch(MethodVisitor mv,
grainier marked this conversation as resolved.
Show resolved Hide resolved
int nameRegIndex,
Set<BIRTypeDefinition> nodes,
Label defaultCaseLabel) {
mv.visitVarInsn(ILOAD, nameRegIndex);
// Create labels for the cases
Map<String, Label> labelFieldMapping = new LinkedHashMap<>();
Map<Integer, Label> labelHashMapping = new LinkedHashMap<>();
for (BIRTypeDefinition node : nodes) {
if (node != null) {
BType type = node.type;
String fieldName = getTypeFieldName(node.internalName.value);
Integer typeHash = typeHashVisitor.visit(type);
boolean fieldExists = labelFieldMapping.containsKey(fieldName);
boolean hashExists = labelHashMapping.containsKey(typeHash);
if (!fieldExists && !hashExists) {
Label label = new Label();
labelFieldMapping.put(fieldName, label);
labelHashMapping.put(typeHash, label);
} else {
assert fieldExists && hashExists; // hashing issues.
}
typeHashVisitor.reset();
}
}
int[] hashes = labelHashMapping.keySet().stream().mapToInt(Integer::intValue).toArray();
Label[] labels = labelHashMapping.values().toArray(new Label[0]);
mv.visitLookupSwitchInsn(defaultCaseLabel, hashes, labels);
return labelFieldMapping;
}

// -------------------------------------------------------
// Runtime value creation methods
// -------------------------------------------------------
Expand Down Expand Up @@ -1856,13 +1935,31 @@ private void loadTupleType(MethodVisitor mv, BTupleType bType) {
* @param bType user defined type
*/
private void loadUserDefinedType(MethodVisitor mv, BType bType) {
BTypeSymbol typeSymbol = bType.tsymbol.isTypeParamResolved ? bType.tsymbol.typeParamTSymbol : bType.tsymbol;
BType typeToLoad = bType.tsymbol.isTypeParamResolved ? typeSymbol.type : bType;
PackageID packageID = typeSymbol.pkgID;
String typeOwner = JvmCodeGenUtil.getPackageName(packageID) + MODULE_INIT_CLASS_NAME;
String fieldName = getTypeFieldName(toNameString(typeToLoad));

PackageID packageID = bType.tsymbol.pkgID;
// if name contains $anon and doesn't belong to the same package, load type using getAnonType() method.
if (!this.packageID.equals(packageID) &&
(fieldName.contains(BLangAnonymousModelHelper.ANON_PREFIX)
|| Symbols.isFlagOn(typeToLoad.flags, Flags.ANONYMOUS))) {
Integer hash = typeHashVisitor.visit(typeToLoad);
String shape = typeToLoad.toString();
typeHashVisitor.reset();

String typeOwner = JvmCodeGenUtil.getPackageName(packageID) + MODULE_INIT_CLASS_NAME;
String fieldName = getTypeFieldName(toNameString(bType));
mv.visitTypeInsn(NEW, typeOwner);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, typeOwner, JVM_INIT_METHOD, "()V", false);

mv.visitFieldInsn(GETSTATIC, typeOwner, fieldName, String.format("L%s;", TYPE));
mv.visitLdcInsn(hash);
mv.visitLdcInsn(String.format("Package: %s, TypeName: %s, Shape: %s", typeOwner, fieldName, shape));
mv.visitMethodInsn(INVOKEVIRTUAL, typeOwner, GET_ANON_TYPE,
String.format("(IL%s;)L%s;", STRING_VALUE, TYPE), false);
} else {
mv.visitFieldInsn(GETSTATIC, typeOwner, fieldName, String.format("L%s;", TYPE));
}
}

/**
Expand All @@ -1871,7 +1968,7 @@ private void loadUserDefinedType(MethodVisitor mv, BType bType) {
* @param typeName type name
* @return name of the field that holds the type instance
*/
private String getTypeFieldName(String typeName) {
private static String getTypeFieldName(String typeName) {

return String.format("$type$%s", typeName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector;
import org.wso2.ballerinalang.compiler.bir.codegen.internal.FieldNameHashComparator;
import org.wso2.ballerinalang.compiler.bir.codegen.internal.NameHashComparator;
import org.wso2.ballerinalang.compiler.bir.codegen.internal.TypeHashComparator;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.BIRFunctionWrapper;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.ExternalMethodGen;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JFieldBIRFunction;
Expand Down Expand Up @@ -144,6 +145,7 @@ class JvmValueGen {

static final FieldNameHashComparator FIELD_NAME_HASH_COMPARATOR = new FieldNameHashComparator();
static final NameHashComparator NAME_HASH_COMPARATOR = new NameHashComparator();
static final TypeHashComparator TYPE_HASH_COMPARATOR = new TypeHashComparator();
static final String ENCODED_RECORD_INIT =
IdentifierUtils.encodeFunctionIdentifier(Names.INIT_FUNCTION_SUFFIX.value);
private final BIRNode.BIRPackage module;
Expand Down Expand Up @@ -668,7 +670,7 @@ private byte[] createRecordValueClass(BRecordType recordType, String className,
} else {
cw.visitSource(className, null);
}
JvmTypeGen jvmTypeGen = new JvmTypeGen(stringConstantsGen);
JvmTypeGen jvmTypeGen = new JvmTypeGen(stringConstantsGen, module.packageID);
JvmCastGen jvmCastGen = new JvmCastGen(jvmPackageGen.symbolTable, jvmTypeGen);
LambdaGen lambdaGen = new LambdaGen(jvmPackageGen, jvmCastGen);
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className,
Expand Down Expand Up @@ -1383,7 +1385,7 @@ private byte[] createObjectValueClass(BObjectType objectType, String className,
ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES);
cw.visitSource(typeDef.pos.lineRange().filePath(), null);

JvmTypeGen jvmTypeGen = new JvmTypeGen(stringConstantsGen);
JvmTypeGen jvmTypeGen = new JvmTypeGen(stringConstantsGen, module.packageID);
JvmCastGen jvmCastGen = new JvmCastGen(jvmPackageGen.symbolTable, jvmTypeGen);
LambdaGen lambdaGen = new LambdaGen(jvmPackageGen, jvmCastGen);
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className, null, ABSTRACT_OBJECT_VALUE, new String[]{B_OBJECT});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.ballerinalang.compiler.bir.codegen.internal;

import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRTypeDefinition;
import org.wso2.ballerinalang.compiler.semantics.analyzer.TypeHashVisitor;

import java.util.Comparator;

/**
* BType hash comparator to sort BIRTypeDefinitions according its type hash code.
*
* @since 2.0.0
*/
public class TypeHashComparator implements Comparator<BIRTypeDefinition> {

private final TypeHashVisitor typeHashVisitor = new TypeHashVisitor();

@Override
public int compare(BIRTypeDefinition o1, BIRTypeDefinition o2) {
Integer o1TypeHash = typeHashVisitor.visit(o1.type);
typeHashVisitor.reset();
Integer o2TypeHash = typeHashVisitor.visit(o2.type);
typeHashVisitor.reset();
return Integer.compare(o1TypeHash, o2TypeHash);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public void generateConfigMapper(List<PackageID> imprtMods, BIRNode.BIRPackage p
mv.visitEnd();

generateConfigInit(cw, moduleInitClass, imprtMods, pkg.packageID);
populateConfigDataMethod(cw, moduleInitClass, pkg, new JvmTypeGen(stringConstantsGen));
populateConfigDataMethod(cw, moduleInitClass, pkg, new JvmTypeGen(stringConstantsGen, pkg.packageID));
cw.visitEnd();
jarEntries.put(innerClassName + ".class", cw.toByteArray());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,18 @@ public class BLangAnonymousModelHelper {
private Map<PackageID, Integer> intersectionRecordCount;
private Map<PackageID, Integer> intersectionErrorCount;

private static final String ANON_TYPE = "$anonType$";
public static final String ANON_PREFIX = "$anon";
private static final String ANON_TYPE = ANON_PREFIX + "Type$";
public static final String LAMBDA = "$lambda$";
private static final String SERVICE = "$$service$";
private static final String ANON_SERVICE = "$anonService$";
private static final String BUILTIN_ANON_TYPE = "$anonType$builtin$";
private static final String ANON_SERVICE = ANON_PREFIX + "Service$";
private static final String BUILTIN_ANON_TYPE = ANON_PREFIX + "Type$builtin$";
private static final String BUILTIN_LAMBDA = "$lambda$builtin$";
private static final String FORK = "$fork$";
private static final String ANON_TYPE_ID = "$anonTypeid$";
private static final String ANON_TYPE_ID = ANON_PREFIX + "Typeid$";
private static final String RAW_TEMPLATE_TYPE = "$rawTemplate$";
private static final String ANON_INTERSECTION_RECORD = "$anonIntersectionRecordType$";
private static final String ANON_INTERSECTION_ERROR_TYPE = "$anonIntersectionErrorType$";
private static final String ANON_INTERSECTION_RECORD = ANON_PREFIX + "IntersectionRecordType$";
private static final String ANON_INTERSECTION_ERROR_TYPE = ANON_PREFIX + "IntersectionErrorType$";
private static final String TUPLE_VAR = "$tupleVar$";
private static final String RECORD_VAR = "$recordVar$";
private static final String ERROR_VAR = "$errorVar$";
Expand Down
Loading