diff --git a/.github/workflows/pull_request_full_build.yml b/.github/workflows/pull_request_full_build.yml index 4a208fac63f2..78561ea7b48d 100644 --- a/.github/workflows/pull_request_full_build.yml +++ b/.github/workflows/pull_request_full_build.yml @@ -92,6 +92,12 @@ jobs: do git clone https://github.com/ballerina-platform/${module_name}.git; \ done +# - name: Checkout non-default branch +# run: | +# for module_name in $(jq -r '.standard_library| .[] | select(.level==${{ matrix.level }}) | .name' extensions.json); do \ +# cd $module_name && git fetch origin && git checkout -t origin/typeDesc-stmt || : && cd ..; \ +# done + - name: Update Lang Version in Module run: | for module_name in $(jq -r '.standard_library| .[] | select(.level==${{ matrix.level }}) | .name' extensions.json); do \ diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java index e4758fd5e8b8..6320f8943037 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java @@ -209,6 +209,10 @@ private void computeStringRepresentation() { if (cachedToString != null) { return; } + if (typeName != null && !typeName.isEmpty()) { + cachedToString = typeName; + return; + } StringBuilder stringRep = new StringBuilder("[").append(tupleTypes.stream().map(Type::toString).collect(Collectors.joining(","))); if (restType != null) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/utils/MapUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/utils/MapUtils.java index 2ae27c4cd2cb..f933da70275a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/utils/MapUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/utils/MapUtils.java @@ -53,7 +53,7 @@ private MapUtils() { } public static void handleMapStore(MapValue mapValue, BString fieldName, Object value) { - updateMapValue(TypeUtils.getImpliedType(mapValue.getType()), mapValue, fieldName, value); + updateMapValue(mapValue.getType(), mapValue, fieldName, value); } public static void handleInherentTypeViolatingMapUpdate(Object value, BMapType mapType) { @@ -149,7 +149,7 @@ public static void checkIsMapOnlyOperation(Type mapType, String op) { private static void updateMapValue(Type mapType, MapValue mapValue, BString fieldName, Object value) { - + mapType = TypeUtils.getImpliedType(mapType); switch (mapType.getTag()) { case TypeTags.MAP_TAG: handleInherentTypeViolatingMapUpdate(value, (BMapType) mapType); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java index c9ba580378da..f6e731c095dd 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java @@ -288,11 +288,8 @@ private static BIntersectionType setImmutableIntersectionType(Type type, Set[] closures; public MapValue annotations; private BTypedesc typedesc; @@ -63,14 +62,8 @@ public TypedescValueImpl(Type describingType) { this.describingType = describingType; } - public TypedescValueImpl(Type describingType, MapValue[] closures) { - this.type = new BTypedescType(describingType); - this.describingType = describingType; - this.closures = closures; - } - - public TypedescValueImpl(Type describingType, MapValue[] closures, MapValue annotations) { - this(describingType, closures); + public TypedescValueImpl(Type describingType, MapValue annotations) { + this(describingType); this.annotations = annotations; ((BAnnotatableType) describingType).setAnnotations(annotations); } diff --git a/compiler/ballerina-lang/spotbugs-exclude.xml b/compiler/ballerina-lang/spotbugs-exclude.xml index 01f5d928a3e3..dd7f9880fb53 100644 --- a/compiler/ballerina-lang/spotbugs-exclude.xml +++ b/compiler/ballerina-lang/spotbugs-exclude.xml @@ -500,4 +500,9 @@ + + + + + diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java index b834de6199f8..36df9609b99a 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java @@ -60,6 +60,7 @@ import org.wso2.ballerinalang.compiler.bir.optimizer.BIROptimizer; import org.wso2.ballerinalang.compiler.diagnostic.BLangDiagnosticLocation; import org.wso2.ballerinalang.compiler.semantics.analyzer.Types; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BAnnotationSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BAttachedFunction; @@ -69,6 +70,7 @@ import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableTypeSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BObjectTypeSymbol; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.BPackageSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BResourceFunction; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BResourcePathSegmentSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BServiceSymbol; @@ -85,6 +87,7 @@ import org.wso2.ballerinalang.compiler.semantics.model.types.BTableType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.semantics.model.types.BTypeReferenceType; +import org.wso2.ballerinalang.compiler.semantics.model.types.BTypedescType; import org.wso2.ballerinalang.compiler.semantics.model.types.BUnionType; import org.wso2.ballerinalang.compiler.tree.BLangAnnotation; import org.wso2.ballerinalang.compiler.tree.BLangAnnotationAttachment; @@ -236,6 +239,7 @@ public class BIRGen extends BLangNodeVisitor { new CompilerContext.Key<>(); public static final String DEFAULT_WORKER_NAME = "function"; + private static final String TYPEDESC = "$typedesc$"; private BIRGenEnv env; private final Names names; private final SymbolTable symTable; @@ -1633,16 +1637,14 @@ public void visit(BLangMapLiteral astMapLiteralExpr) { BType type = astMapLiteralExpr.getBType(); this.env.isInArrayOrStructure++; - visitTypedesc(astMapLiteralExpr.pos, type, Collections.emptyList(), getAnnotations(type.tsymbol, this.env)); - BIRVariableDcl tempVarDcl = - new BIRVariableDcl(astMapLiteralExpr.getBType(), this.env.nextLocalVarId(names), - VarScope.FUNCTION, VarKind.TEMP); + BIRVariableDcl tempVarDcl = new BIRVariableDcl(type, this.env.nextLocalVarId(names), VarScope.FUNCTION, + VarKind.TEMP); this.env.enclFunc.localVars.add(tempVarDcl); BIROperand toVarRef = new BIROperand(tempVarDcl); - - setScopeAndEmit(new BIRNonTerminator.NewStructure(astMapLiteralExpr.pos, toVarRef, this.env.targetOperand, - generateMappingConstructorEntries(astMapLiteralExpr.fields))); + BIROperand typeDesc = new BIROperand(getTypedescVariable(type, astMapLiteralExpr.pos)); + setScopeAndEmit(createNewStructureInst(typeDesc, generateMappingConstructorEntries(astMapLiteralExpr.fields), + toVarRef, astMapLiteralExpr.pos)); this.env.targetOperand = toVarRef; this.env.isInArrayOrStructure--; } @@ -1667,19 +1669,15 @@ public void visit(BLangTypeConversionExpr astTypeConversionExpr) { public void visit(BLangStructLiteral astStructLiteralExpr) { this.env.isInArrayOrStructure++; BType type = astStructLiteralExpr.getBType(); - visitTypedesc(astStructLiteralExpr.pos, type, Collections.emptyList(), getAnnotations(type.tsymbol, this.env)); - - BIRVariableDcl tempVarDcl = new BIRVariableDcl(astStructLiteralExpr.getBType(), - this.env.nextLocalVarId(names), VarScope.FUNCTION, VarKind.TEMP); + BIRVariableDcl tempVarDcl = new BIRVariableDcl(astStructLiteralExpr.getBType(), this.env.nextLocalVarId(names), + VarScope.FUNCTION, VarKind.TEMP); this.env.enclFunc.localVars.add(tempVarDcl); BIROperand toVarRef = new BIROperand(tempVarDcl); - - BIRNonTerminator.NewStructure instruction = - new BIRNonTerminator.NewStructure(astStructLiteralExpr.pos, toVarRef, this.env.targetOperand, - generateMappingConstructorEntries(astStructLiteralExpr.fields)); - setScopeAndEmit(instruction); - + BIROperand typeDesc = new BIROperand(getTypedescVariable(type, astStructLiteralExpr.pos)); + List fields = + generateMappingConstructorEntries(astStructLiteralExpr.fields); + setScopeAndEmit(createNewStructureInst(typeDesc, fields, toVarRef, astStructLiteralExpr.pos)); this.env.targetOperand = toVarRef; this.env.isInArrayOrStructure--; } @@ -1694,7 +1692,7 @@ public void visit(BLangTypeInit connectorInitExpr) { BType objectType = getEffectiveObjectType(exprType); BTypeSymbol objectTypeSymbol = Types.getImpliedType(objectType).tsymbol; BIRNonTerminator.NewInstance instruction; - if (isInSamePackage(objectTypeSymbol, env.enclPkg.packageID)) { + if (isInSameModule(objectTypeSymbol, env.enclPkg.packageID)) { BIRTypeDefinition def = typeDefs.get(objectTypeSymbol); instruction = new BIRNonTerminator.NewInstance(connectorInitExpr.pos, def, toVarRef, objectType); } else { @@ -1706,8 +1704,8 @@ public void visit(BLangTypeInit connectorInitExpr) { this.env.targetOperand = toVarRef; } - private boolean isInSamePackage(BSymbol objectTypeSymbol, PackageID packageID) { - return objectTypeSymbol.pkgID.equals(packageID); + private boolean isInSameModule(BSymbol symbol, PackageID packageID) { + return symbol.pkgID.equals(packageID); } @Override @@ -1716,17 +1714,11 @@ public void visit(BLangSimpleVarRef.BLangFieldVarRef fieldVarRef) { @Override public void visit(BLangArrayLiteral astArrayLiteralExpr) { - BType bType = astArrayLiteralExpr.getBType(); - if (bType.tag == TypeTags.TUPLE) { - visitTypedesc(astArrayLiteralExpr.pos, bType); - } generateListConstructorExpr(astArrayLiteralExpr); } @Override public void visit(BLangTupleLiteral tupleLiteral) { - BType type = tupleLiteral.getBType(); - visitTypedesc(tupleLiteral.pos, type, getAnnotations(type.tsymbol, this.env)); generateListConstructorExpr(tupleLiteral); } @@ -1737,10 +1729,6 @@ public void visit(BLangGroupExpr groupExpr) { @Override public void visit(BLangJSONArrayLiteral jsonArrayLiteralExpr) { - BType bType = jsonArrayLiteralExpr.getBType(); - if (bType.tag == TypeTags.TUPLE) { - visitTypedesc(jsonArrayLiteralExpr.pos, bType); - } generateListConstructorExpr(jsonArrayLiteralExpr); } @@ -1944,7 +1932,7 @@ private BIRGlobalVariableDcl getVarRef(BLangPackageVarRef astPackageVarRefExpr) this.globalVarMap.put(symbol, globalVarDcl); } - if (!isInSamePackage(astPackageVarRefExpr.varSymbol, env.enclPkg.packageID) || + if (!isInSameModule(astPackageVarRefExpr.varSymbol, env.enclPkg.packageID) || env.enclPkg.packageID.isTestPkg) { this.env.enclPkg.importedGlobalVarsDummyVarDcls.add(globalVarDcl); } @@ -2028,15 +2016,17 @@ public void visit(BLangWaitExpr waitExpr) { @Override public void visit(BLangWaitForAllExpr.BLangWaitLiteral waitLiteral) { this.env.isInArrayOrStructure++; - visitTypedesc(waitLiteral.pos, waitLiteral.getBType()); BIRBasicBlock thenBB = new BIRBasicBlock(this.env.nextBBId()); addToTrapStack(thenBB); - - BIRVariableDcl tempVarDcl = new BIRVariableDcl(waitLiteral.getBType(), - this.env.nextLocalVarId(names), VarScope.FUNCTION, VarKind.TEMP); + BType type = waitLiteral.getBType(); + BIRVariableDcl tempVarDcl = new BIRVariableDcl(type, this.env.nextLocalVarId(names), VarScope.FUNCTION, + VarKind.TEMP); this.env.enclFunc.localVars.add(tempVarDcl); BIROperand toVarRef = new BIROperand(tempVarDcl); - setScopeAndEmit(new BIRNonTerminator.NewStructure(waitLiteral.pos, toVarRef, this.env.targetOperand)); + Location pos = waitLiteral.pos; + + BIROperand typeDesc = new BIROperand(getTypedescVariable(type, pos)); + setScopeAndEmit(createNewStructureInst(typeDesc, new ArrayList<>(), toVarRef, pos)); this.env.targetOperand = toVarRef; List keys = new ArrayList<>(); @@ -2048,7 +2038,7 @@ public void visit(BLangWaitForAllExpr.BLangWaitLiteral waitLiteral) { BIROperand valueRegIndex = this.env.targetOperand; valueExprs.add(valueRegIndex); } - this.env.enclBB.terminator = new BIRTerminator.WaitAll(waitLiteral.pos, toVarRef, keys, + this.env.enclBB.terminator = new BIRTerminator.WaitAll(pos, toVarRef, keys, valueExprs, thenBB, this.currentScope); this.env.targetOperand = toVarRef; this.env.enclFunc.basicBlocks.add(thenBB); @@ -2244,14 +2234,7 @@ public void visit(BLangXMLAccessExpr xmlAccessExpr) { @Override public void visit(BLangTypedescExpr accessExpr) { - BIRVariableDcl tempVarDcl = - new BIRVariableDcl(accessExpr.getBType(), this.env.nextLocalVarId(names), VarScope.FUNCTION, - VarKind.TEMP); - this.env.enclFunc.localVars.add(tempVarDcl); - BIROperand toVarRef = new BIROperand(tempVarDcl); - setScopeAndEmit(new BIRNonTerminator.NewTypeDesc(accessExpr.pos, toVarRef, accessExpr.resolvedType, - Collections.emptyList())); - this.env.targetOperand = toVarRef; + this.env.targetOperand = new BIROperand(getTypedescVariable(accessExpr.resolvedType, accessExpr.pos)); } @Override @@ -2300,30 +2283,7 @@ public void visit(BLangTableConstructorExpr tableConstructorExpr) { public void visit(BLangSimpleVarRef.BLangTypeLoad typeLoad) { BType type = typeLoad.symbol.tag == SymTag.TYPE_DEF ? ((BTypeDefinitionSymbol) typeLoad.symbol).referenceType : typeLoad.symbol.type; - visitTypedesc(typeLoad.pos, type); - } - - private void visitTypedesc(Location pos, BType type) { - visitTypedesc(pos, type, Collections.emptyList(), null); - } - - private void visitTypedesc(Location pos, BType type, BIROperand annotations) { - visitTypedesc(pos, type, Collections.emptyList(), annotations); - } - - private void visitTypedesc(Location pos, BType type, List varDcls, BIROperand annotations) { - BIRVariableDcl tempVarDcl = new BIRVariableDcl(symTable.typeDesc, this.env.nextLocalVarId(names), - VarScope.FUNCTION, VarKind.TEMP); - BIRGenEnv env = this.env; - env.enclFunc.localVars.add(tempVarDcl); - BIROperand toVarRef = new BIROperand(tempVarDcl); - if (annotations != null) { - setScopeAndEmit(new BIRNonTerminator.NewTypeDesc(pos, toVarRef, type, varDcls, annotations)); - env.targetOperand = toVarRef; - return; - } - setScopeAndEmit(new BIRNonTerminator.NewTypeDesc(pos, toVarRef, type, Collections.emptyList())); - env.targetOperand = toVarRef; + env.targetOperand = new BIROperand(getTypedescVariable(type, typeLoad.pos)); } @Override @@ -2442,6 +2402,136 @@ public void visit(BLangRegExpTemplateLiteral regExpTemplateLiteral) { this.env.targetOperand = toVarRef; } + private BIRNonTerminator.NewStructure createNewStructureInst(BIROperand typeDesc, + List fields, + BIROperand toVarRef, Location pos) { + return new BIRNonTerminator.NewStructure(pos, toVarRef, typeDesc, fields); + } + + private BIRVariableDcl getTypedescVariable(BType type, Location pos) { + if (type.tag == TypeTags.TYPEREFDESC) { + BType referredType = ((BTypeReferenceType) type).referredType; + int tag = referredType.tag; + if (tag == TypeTags.RECORD) { + type = referredType; + } + } + + BIRVariableDcl variableDcl = findInPackageScope(type); + if (variableDcl != null && variableDcl.initialized) { + return variableDcl; + } + + variableDcl = findInLocalSymbolVarMap(type, env.symbolVarMap); + if (variableDcl != null && variableDcl.initialized) { + return variableDcl; + } + + variableDcl = findInGlobalSymbolVarMap(type, this.globalVarMap); + if (variableDcl != null && variableDcl.initialized) { + return variableDcl; + } + + // Create new type desc instruction if the typedesc variable is not found + // TODO: we need to handle duplicate typedesc creation for some cases. + // eg: function params ie `foo(record {int a;})` + createNewTypedescInst(type, pos); + return this.env.targetOperand.variableDcl; + } + + private BIRVariableDcl findInPackageScope(BType type) { + BTypeSymbol typeSymbol = type.tsymbol; + if (typeSymbol == null || typeSymbol.owner.tag != SymTag.PACKAGE || + isInSameModule(typeSymbol, env.enclPkg.packageID)) { + return null; + } + BPackageSymbol packageSymbol = (BPackageSymbol) typeSymbol.owner; + Scope.ScopeEntry scopeEntry = + packageSymbol.scope.lookup(new Name(TYPEDESC + typeSymbol.name.value)); + BSymbol symbol = scopeEntry.symbol; + return symbol != null ? getVarRef(createPackageVarRef(symbol)) : null; + } + + private BLangPackageVarRef createPackageVarRef(BSymbol symbol) { + BLangPackageVarRef packageVarRef = new BLangPackageVarRef((BVarSymbol) symbol); + packageVarRef.pos = symbol.pos; + packageVarRef.setBType(symbol.getType()); + return packageVarRef; + } + + private BIRVariableDcl findInLocalSymbolVarMap(BType type, Map varMap) { + for (Map.Entry entry : varMap.entrySet()) { + if (isMatchingTypeDescSymbol(entry.getKey(), type)) { + return varMap.get(entry.getKey()); + } + } + return null; + } + + private BIRVariableDcl findInGlobalSymbolVarMap(BType type, Map varMap) { + for (Map.Entry entry : varMap.entrySet()) { + BSymbol varSymbol = entry.getKey(); + if (isMatchingTypeDescSymbol(varSymbol, type)) { + BIRGlobalVariableDcl globalVarDcl = varMap.get(varSymbol); + if (!isInSameModule(varSymbol, env.enclPkg.packageID) || env.enclPkg.packageID.isTestPkg) { + this.env.enclPkg.importedGlobalVarsDummyVarDcls.add(globalVarDcl); + } + return globalVarDcl; + } + } + return null; + } + + private boolean isMatchingTypeDescSymbol(BSymbol symbol, BType targetType) { + // ATM there is no proper way to generate the full name of the target typedesc variable for the anonymous + // types because `tsymbol.name.value` is empty for those. + // Hence, we are using the TYPEDESC prefix to identify the typedesc variables and then match type constant type. + if (!symbol.name.value.startsWith(TYPEDESC)) { + return false; + } + BType constraint = ((BTypedescType) symbol.type).constraint; + return targetType == constraint; + } + + private void createNewTypedescInst(BType resolveType, Location position) { + BTypeSymbol typeSymbol = resolveType.tsymbol; + BIRVariableDcl tempVarDcl = createTempVariable(); + BIROperand toVarRef = new BIROperand(tempVarDcl); + + BIRNonTerminator.NewTypeDesc newTypeDesc = createNewTypeDesc(position, toVarRef, resolveType, typeSymbol); + + this.env.targetOperand = toVarRef; + setScopeAndEmit(newTypeDesc); + } + + private BIRVariableDcl createTempVariable() { + BIRVariableDcl tempVarDcl = new BIRVariableDcl(symTable.typeDesc, this.env.nextLocalVarId(names), + VarScope.FUNCTION, VarKind.TEMP); + this.env.enclFunc.localVars.add(tempVarDcl); + return tempVarDcl; + } + + private BIRNonTerminator.NewTypeDesc createNewTypeDesc(Location position, BIROperand toVarRef, BType resolveType, + BTypeSymbol typeSymbol) { + List closures = Collections.emptyList(); + if (typeSymbol != null && typeSymbol.annotations != null) { + BVarSymbol typeAnnotations = typeSymbol.annotations; + BIRVariableDcl annotations = this.env.symbolVarMap.get(typeAnnotations); + BIROperand symbolVarOperand = annotations != null ? + new BIROperand(annotations) : new BIROperand(this.globalVarMap.get(typeAnnotations)); + return new BIRNonTerminator.NewTypeDesc(position, toVarRef, resolveType, closures, symbolVarOperand); + } else { + return new BIRNonTerminator.NewTypeDesc(position, toVarRef, resolveType, closures); + } + } + + private BIRNonTerminator.NewArray createNewArrayInst(BIROperand typeDesc, + List initialValues, + BType listConstructorExprType, BIROperand sizeOp, + BIROperand toVarRef, Location pos) { + return new BIRNonTerminator.NewArray(pos, listConstructorExprType, toVarRef, typeDesc, sizeOp, initialValues); + } + @Override public void visit(BLangReDisjunction reDisjunction) { BIROperand toVarRef = createVarRefOperand(symTable.anydataType); @@ -2716,16 +2806,27 @@ private void generateListConstructorExpr(BLangListConstructorExpr listConstructo this.env.enclFunc.localVars.add(tempVarDcl); BIROperand toVarRef = new BIROperand(tempVarDcl); - long size = -1L; - BIROperand typedescOp = null; - List exprs = listConstructorExpr.exprs; BType listConstructorExprType = listConstructorExpr.getBType(); + + List exprs = listConstructorExpr.exprs; BType referredType = Types.getImpliedType(listConstructorExprType); + BIROperand typeDesc = null; + boolean isRecordArray = false; + if (referredType.tag == TypeTags.TUPLE) { + typeDesc = new BIROperand(getTypedescVariable(listConstructorExprType, listConstructorExpr.pos)); + } else { + BType elementType = ((BArrayType) referredType).getElementType(); + if (Types.getImpliedType(elementType).tag == TypeTags.RECORD) { + typeDesc = new BIROperand(getTypedescVariable(elementType, elementType.tsymbol.pos)); + isRecordArray = true; + } + } + + long size = -1L; if (referredType.tag == TypeTags.ARRAY && ((BArrayType) referredType).state != BArrayState.OPEN) { size = ((BArrayType) referredType).size; } else if (referredType.tag == TypeTags.TUPLE) { - typedescOp = this.env.targetOperand; size = exprs.size(); } @@ -2750,13 +2851,18 @@ private void generateListConstructorExpr(BLangListConstructorExpr listConstructo } if (referredType.tag == TypeTags.TUPLE) { - setScopeAndEmit( - new BIRNonTerminator.NewArray(listConstructorExpr.pos, listConstructorExprType, toVarRef, - typedescOp, sizeOp, initialValues)); + setScopeAndEmit(createNewArrayInst(typeDesc, initialValues, listConstructorExprType, sizeOp, toVarRef, + listConstructorExpr.pos)); + } else { - setScopeAndEmit( - new BIRNonTerminator.NewArray(listConstructorExpr.pos, listConstructorExprType, toVarRef, sizeOp, - initialValues)); + BIRNonTerminator.NewArray newArrayIns = new BIRNonTerminator.NewArray(listConstructorExpr.pos, + listConstructorExprType, toVarRef, sizeOp, initialValues); + // If the referredType is an array type and the element type is record type, then we need to set + // the element typeDesc which will be used to initialize the `ArrayValueImpl` + if (isRecordArray) { + newArrayIns.elementTypedescOp = typeDesc; + } + setScopeAndEmit(newArrayIns); } this.env.targetOperand = toVarRef; this.env.isInArrayOrStructure--; @@ -3063,20 +3169,6 @@ private List getBIRAnnotAttachmentsForASTAnnotAttachmen return annotationAttachments; } - private BIROperand getAnnotations(BTypeSymbol typeSymbol, BIRGenEnv env) { - if (typeSymbol == null || typeSymbol.annotations == null) { - return null; - } - return new BIROperand(getAnnotations(typeSymbol.annotations, env)); - } - - private BIRVariableDcl getAnnotations(BVarSymbol annotations, BIRGenEnv env) { - if (env.symbolVarMap.containsKey(annotations)) { - return env.symbolVarMap.get(annotations); - } - return globalVarMap.get(annotations); - } - private void addReturnBB(Location pos) { if (this.env.returnBB == null) { BIRBasicBlock returnBB = new BIRBasicBlock(this.env.nextBBId()); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java index 8b36b3d02c79..836180fc7b97 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java @@ -64,7 +64,6 @@ public final class JvmConstants { public static final String XML_QNAME = "io/ballerina/runtime/internal/values/XmlQName"; public static final String FUTURE_VALUE = "io/ballerina/runtime/internal/values/FutureValue"; public static final String TYPEDESC_VALUE_IMPL = "io/ballerina/runtime/internal/values/TypedescValueImpl"; - public static final String TYPEDESC_VALUE_IMPL_CLOSURES = "closures"; public static final String TYPEDESC_VALUE = "io/ballerina/runtime/internal/values/TypedescValue"; public static final String HANDLE_VALUE = "io/ballerina/runtime/internal/values/HandleValue"; public static final String LOCK_STORE = "io/ballerina/runtime/internal/lock/BLockStore"; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java index 7ba8024a01db..6a797d33bad5 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java @@ -52,7 +52,6 @@ import org.wso2.ballerinalang.compiler.semantics.model.types.BObjectType; import org.wso2.ballerinalang.compiler.semantics.model.types.BRecordType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; -import org.wso2.ballerinalang.compiler.semantics.model.types.BTypeReferenceType; import org.wso2.ballerinalang.compiler.util.TypeTags; import org.wso2.ballerinalang.util.Flags; @@ -66,7 +65,6 @@ import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.ANEWARRAY; import static org.objectweb.asm.Opcodes.ASTORE; -import static org.objectweb.asm.Opcodes.BIPUSH; import static org.objectweb.asm.Opcodes.CHECKCAST; import static org.objectweb.asm.Opcodes.DADD; import static org.objectweb.asm.Opcodes.DCMPL; @@ -223,7 +221,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MODULE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STRING_AT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STRING_FROM_ARRAY; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_TYPEDESC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_TYPEDESC_OF_OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.HANDLE_MAP_STORE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.HANDLE_TABLE_STORE; @@ -502,9 +499,8 @@ private void generateJLargeArrayIns(int localVarOffset, JLargeArrayInstruction i jvmTypeGen.loadType(this.mv, inst.type); loadListInitialValues(inst); BType elementType = JvmCodeGenUtil.getImpliedType(((BArrayType) instType).eType); - if (elementType.tag == TypeTags.RECORD || (elementType.tag == TypeTags.INTERSECTION && - ((BIntersectionType) elementType).effectiveType.tag == TypeTags.RECORD)) { - visitNewRecordArray(elementType); + if (elementType.tag == TypeTags.RECORD) { + visitNewRecordArray(inst.elementTypedescOp.variableDcl); } else { this.mv.visitMethodInsn(INVOKESPECIAL, ARRAY_VALUE_IMPL, JVM_INIT_METHOD, INIT_ARRAY, false); @@ -1421,7 +1417,7 @@ void generateArrayNewIns(BIRNonTerminator.NewArray inst, int localVarOffset) { BType elementType = JvmCodeGenUtil.getImpliedType(((BArrayType) instType).eType); if (elementType.tag == TypeTags.RECORD) { - visitNewRecordArray(elementType); + visitNewRecordArray(inst.elementTypedescOp.variableDcl); } else { this.mv.visitMethodInsn(INVOKESPECIAL, ARRAY_VALUE_IMPL, JVM_INIT_METHOD, INIT_ARRAY, false); @@ -1437,12 +1433,8 @@ void generateArrayNewIns(BIRNonTerminator.NewArray inst, int localVarOffset) { } } - private void visitNewRecordArray(BType type) { - BType elementType = JvmCodeGenUtil.getImpliedType(type); - String typeOwner = JvmCodeGenUtil.getPackageName(type.tsymbol.pkgID) + MODULE_INIT_CLASS_NAME; - String typedescFieldName = - jvmTypeGen.getTypedescFieldName(toNameString(elementType)); - this.mv.visitFieldInsn(GETSTATIC, typeOwner, typedescFieldName, "L" + TYPEDESC_VALUE + ";"); + private void visitNewRecordArray(BIRNode.BIRVariableDcl elementTypeDesc) { + this.loadVar(elementTypeDesc); this.mv.visitMethodInsn(INVOKESPECIAL, ARRAY_VALUE_IMPL, JVM_INIT_METHOD, INIT_ARRAY_WITH_INITIAL_VALUES, false); } @@ -2000,54 +1992,23 @@ void generateNegateIns(BIRNonTerminator.UnaryOP unaryOp) { } void generateNewTypedescIns(BIRNonTerminator.NewTypeDesc newTypeDesc) { - List closureVars = newTypeDesc.closureVars; - if (isNonReferredRecord(newTypeDesc.type)) { - BType type = JvmCodeGenUtil.getImpliedType(newTypeDesc.type); - PackageID packageID = type.tsymbol.pkgID; - String typeOwner = JvmCodeGenUtil.getPackageName(packageID) + MODULE_INIT_CLASS_NAME; - String fieldName = jvmTypeGen.getTypedescFieldName(toNameString(type)); - mv.visitFieldInsn(GETSTATIC, typeOwner, fieldName, GET_TYPEDESC); - } else { - generateNewTypedescCreate(newTypeDesc.type, closureVars, newTypeDesc.annotations); - } - this.storeToVar(newTypeDesc.lhsOp.variableDcl); - } - - private boolean isNonReferredRecord(BType type) { - if (type.tag != TypeTags.TYPEREFDESC) { - return false; - } - BType referredType = ((BTypeReferenceType) type).referredType; - return referredType.tag == TypeTags.RECORD && - type.getQualifiedTypeName().equals(referredType.getQualifiedTypeName()); - } - - private void generateNewTypedescCreate(BType btype, List closureVars, BIROperand annotations) { - BType type = JvmCodeGenUtil.getImpliedType(btype); String className = TYPEDESC_VALUE_IMPL; + BType type = JvmCodeGenUtil.getImpliedType(newTypeDesc.type); if (type.tag == TypeTags.RECORD) { className = getTypeDescClassName(JvmCodeGenUtil.getPackageName(type.tsymbol.pkgID), toNameString(type)); } this.mv.visitTypeInsn(NEW, className); this.mv.visitInsn(DUP); - jvmTypeGen.loadType(this.mv, btype); - - mv.visitIntInsn(BIPUSH, closureVars.size()); - mv.visitTypeInsn(ANEWARRAY, MAP_VALUE); - for (int i = 0; i < closureVars.size(); i++) { - BIROperand closureVar = closureVars.get(i); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, i); - this.loadVar(closureVar.variableDcl); - mv.visitInsn(AASTORE); - } + jvmTypeGen.loadType(this.mv, newTypeDesc.type); + BIROperand annotations = newTypeDesc.annotations; if (annotations != null) { this.loadVar(annotations.variableDcl); this.mv.visitMethodInsn(INVOKESPECIAL, className, JVM_INIT_METHOD, TYPE_DESC_CONSTRUCTOR_WITH_ANNOTATIONS, - false); + false); } else { this.mv.visitMethodInsn(INVOKESPECIAL, className, JVM_INIT_METHOD, TYPE_DESC_CONSTRUCTOR, false); } + this.storeToVar(newTypeDesc.lhsOp.variableDcl); } void loadVar(BIRNode.BIRVariableDcl varDcl) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java index 98b674a2367a..e1fded1fe2d3 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java @@ -471,8 +471,8 @@ public final class JvmSignatures { public static final String TO_STRING_RETURN = "()L" + STRING_VALUE + ";"; public static final String TUPLE_SET_MEMBERS_METHOD = "(L" + LIST + ";L" + TYPE + ";)V"; public static final String TWO_OBJECTS_ARGS = "(L" + OBJECT + ";L" + OBJECT + ";)V"; - public static final String TYPE_DESC_CONSTRUCTOR = "(L" + TYPE + ";[L" + MAP_VALUE + ";)V"; - public static final String TYPE_DESC_CONSTRUCTOR_WITH_ANNOTATIONS = "(L" + TYPE + ";[L" + MAP_VALUE + ";L" + + public static final String TYPE_DESC_CONSTRUCTOR = "(L" + TYPE + ";)V"; + public static final String TYPE_DESC_CONSTRUCTOR_WITH_ANNOTATIONS = "(L" + TYPE + ";L" + MAP_VALUE + ";)V"; public static final String TYPE_PARAMETER = "(L" + TYPE + ";)V"; public static final String VALUE_OF_JSTRING = "(L" + OBJECT + ";)L" + STRING_VALUE + ";"; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java index 491a1fa6b564..b2b2e467ec01 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java @@ -239,7 +239,11 @@ void generateUserDefinedTypeFields(ClassWriter cw, List typeD } String name = typeDef.internalName.value; generateTypeField(cw, name); - generateTypedescField(cw, name); + // Exclude field generation for typedesc when generating fields for user defined types since + // those fields will be generated when visiting global variables + if (bTypeTag != TypeTags.RECORD && bTypeTag != TypeTags.TUPLE) { + generateTypedescField(cw, name); + } } } @@ -847,7 +851,7 @@ public static String getTypeFieldName(String typeName) { } public String getTypedescFieldName(String name) { - return "$typedesce$" + name; + return "$typedesc$" + name; } private void loadFutureType(MethodVisitor mv, BFutureType bType) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java index 7d97b9ab36c9..a23cd4f964de 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java @@ -64,10 +64,8 @@ import static org.objectweb.asm.Opcodes.IRETURN; import static org.objectweb.asm.Opcodes.ISTORE; import static org.objectweb.asm.Opcodes.NEW; -import static org.objectweb.asm.Opcodes.POP; import static org.objectweb.asm.Opcodes.PUTFIELD; import static org.objectweb.asm.Opcodes.RETURN; -import static org.objectweb.asm.Opcodes.SWAP; import static org.objectweb.asm.Opcodes.V21; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.toNameString; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ABSTRACT_OBJECT_VALUE; @@ -87,13 +85,11 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TYPEDESC_CLASS_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TYPEDESC_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TYPEDESC_VALUE_IMPL; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TYPEDESC_VALUE_IMPL_CLOSURES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TYPE_IMPL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.UNSUPPORTED_OPERATION_EXCEPTION; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.VALUE_CLASS_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmDesugarPhase.addDefaultableBooleanVarsToSignature; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.CAST_B_MAPPING_INITIAL_VALUE_ENTRY; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MAP_ARRAY; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MAP_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_TYPEDESC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INSTANTIATE; @@ -257,14 +253,6 @@ private void createInstantiateMethodWithInitialValues(ClassWriter cw, BRecordTyp mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, className, JVM_INIT_METHOD, INIT_TYPEDESC, false); - // Invoke the init-function of this type. - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(SWAP); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, TYPEDESC_VALUE_IMPL, TYPEDESC_VALUE_IMPL_CLOSURES, - GET_MAP_ARRAY); - mv.visitInsn(POP); - // Invoke the init-function of this type. String valueClassName; List attachedFuncs = typeDef.attachedFuncs; @@ -336,7 +324,6 @@ private void createTypeDescConstructor(ClassWriter cw, String className) { // load type mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); // invoke `super(type)`; mv.visitMethodInsn(INVOKESPECIAL, TYPEDESC_VALUE_IMPL, JVM_INIT_METHOD, descriptor, false); @@ -351,16 +338,14 @@ private void createTypeDescConstructorWithAnnotations(ClassWriter cw, String nam mv.visitCode(); mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, 2); mv.visitFieldInsn(PUTFIELD, name, ANNOTATIONS_FIELD, GET_MAP_VALUE); // load super mv.visitVarInsn(ALOAD, 0); // load type mv.visitVarInsn(ALOAD, 1); - // load closures - mv.visitVarInsn(ALOAD, 2); // load annotations - mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, 2); // invoke `super(type)`; mv.visitMethodInsn(INVOKESPECIAL, TYPEDESC_VALUE_IMPL, JVM_INIT_METHOD, TYPE_DESC_CONSTRUCTOR_WITH_ANNOTATIONS, false); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeArrayInstruction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeArrayInstruction.java index 94fc56ae626f..b97694085c6c 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeArrayInstruction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeArrayInstruction.java @@ -31,6 +31,7 @@ public class JLargeArrayInstruction extends JInstruction { public BIROperand typedescOp; + public BIROperand elementTypedescOp; public BIROperand sizeOp; public BType type; public BIROperand values; @@ -46,9 +47,10 @@ public JLargeArrayInstruction(Location location, BType type, BIROperand lhsOp, B } public JLargeArrayInstruction(Location location, BType type, BIROperand lhsOp, BIROperand typedescOp, - BIROperand sizeOp, BIROperand values) { + BIROperand elementTypedescOp, BIROperand sizeOp, BIROperand values) { this(location, type, lhsOp, sizeOp, values); this.typedescOp = typedescOp; + this.elementTypedescOp = elementTypedescOp; } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java index 579e108d25eb..e2bc41b00c02 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java @@ -18,6 +18,7 @@ package org.wso2.ballerinalang.compiler.bir.codegen.optimizer; +import org.ballerinalang.model.elements.Flag; import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.symbols.SymbolOrigin; import org.wso2.ballerinalang.compiler.bir.BIRGenUtils; @@ -43,21 +44,32 @@ import org.wso2.ballerinalang.compiler.bir.model.VarKind; import org.wso2.ballerinalang.compiler.bir.model.VarScope; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.BTypeSymbol; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.BVarSymbol; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.SymTag; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols; import org.wso2.ballerinalang.compiler.semantics.model.types.BInvokableType; +import org.wso2.ballerinalang.compiler.semantics.model.types.BTupleMember; +import org.wso2.ballerinalang.compiler.semantics.model.types.BTupleType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.semantics.model.types.BUnionType; import org.wso2.ballerinalang.compiler.util.Name; +import org.wso2.ballerinalang.compiler.util.Names; +import org.wso2.ballerinalang.util.Flags; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; +import static org.ballerinalang.model.symbols.SymbolOrigin.VIRTUAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.wso2.ballerinalang.compiler.bir.BIRGenUtils.rearrangeBasicBlocks; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LARGE_STRUCTURE_UTILS; @@ -75,13 +87,17 @@ public class LargeMethodOptimizer { private static final Name DEFAULT_WORKER_NAME = new Name("function"); private static final String OBJECT_INITIALIZATION_FUNCTION_NAME = "$init$"; private static final String SPLIT_METHOD = "$split$method$_"; + private static final String ARG_INDEX = "%argIndex"; + private static final String ARG_TUPLE_SIZE = "%argTupleSize"; + private static final String ARG_TUPLE_TYPEDESC = "%argTupleTypeDesc_"; + private static final String ARG_TUPLE = "%argTuple_"; private final SymbolTable symbolTable; // splits are done only if the original function has more instructions than the below number private static final int FUNCTION_INSTRUCTION_COUNT_THRESHOLD = 1000; // splits are done only if the newly created method will contain more instructions than the below number private static final int SPLIT_INSTRUCTION_COUNT_THRESHOLD = 25; // splits are done only if the newly created method will have less function arguments than the below number - private static final int MAX_SPLIT_FUNCTION_ARG_COUNT = 125; + private static final int MAX_SPLIT_FUNCTION_ARG_COUNT = 93; // total least no. of terminators and non-terminators that should be there to make the periodic split private static final int INS_COUNT_PERIODIC_SPLIT_THRESHOLD = 500; // current BIR package id @@ -90,6 +106,10 @@ public class LargeMethodOptimizer { private int splitFuncNum; // newly created temporary variable number to handle split function return value private int splitTempVarNum; + // next argument tuple and tuple typedesc indexes used to compress arguments when the split function arg + // count exceeds `MAX_SPLIT_FUNCTION_ARG_COUNT` + private int argTupleTypeDescIndex; + private int argTupleIndex; public LargeMethodOptimizer(SymbolTable symbolTable) { this.symbolTable = symbolTable; @@ -99,6 +119,8 @@ public void splitLargeBIRFunctions(BIRPackage birPkg) { currentPackageId = birPkg.packageID; splitFuncNum = 0; splitTempVarNum = 0; + argTupleTypeDescIndex = 0; + argTupleIndex = 0; List newlyAddedBIRFunctions = new ArrayList<>(); for (BIRFunction function : birPkg.functions) { @@ -171,6 +193,13 @@ private void periodicSplitMap(BIRFunction parentFunc, List newlyAdd ParentFuncEnv parentFuncEnv = new ParentFuncEnv(bbs.get(newMapInsBBNum + 1)); SplitFuncEnv splitFuncEnv = new SplitFuncEnv(getTempVarsForArraySplit(), fromAttachedFunction); + // add large arg restore instructions + int instIndex = skipLargeArgRestoreInstsAndGetIndex(bbs.getFirst()); + for (BIRNonTerminator ins : bbs.getFirst().instructions.subList(0, instIndex)) { + parentFuncEnv.parentFuncNewInsList.add(ins); + parentFuncEnv.parentFuncLocalVarList.add(ins.lhsOp.variableDcl); + } + parentFuncEnv.returnOperand = mapIns.lhsOp; BIRVariableDcl handleArray = new BIRVariableDcl(null, symbolTable.handleType, new Name("%mapEntryArray"), VarScope.FUNCTION, VarKind.TEMP, null); @@ -190,10 +219,6 @@ private void periodicSplitMap(BIRFunction parentFunc, List newlyAdd handleArrayOperand, birOperands, mapValuesOperands, globalAndArgVarKeyOrValueLhsOperands, mapKeyOperandLocations); - // add the constant load array size operand instruction - parentFuncEnv.parentFuncNewInsList.add(bbs.getFirst().instructions.getFirst()); - parentFuncEnv.parentFuncLocalVarList.add(bbs.getFirst().instructions.getFirst().lhsOp.variableDcl); - splitParentFuncForPeriodicMapSplits(parentFunc, newlyAddingFunctions, fromAttachedFunction, bbs, newMapInsBBNum, newMapInsNumInRelevantBB, handleArray, handleArrayOperand, birOperands, splitFuncEnv, parentFuncEnv, mapValuesOperands, @@ -242,13 +267,21 @@ private void periodicSplitArray(BIRFunction parentFunc, List newlyA ParentFuncEnv parentFuncEnv = new ParentFuncEnv(bbs.get(newArrayInsBBNum + 1)); SplitFuncEnv splitFuncEnv = new SplitFuncEnv(getTempVarsForArraySplit(), fromAttachedFunction); + // add large arg restore and constant load array size operand instruction + int instIndex = skipLargeArgRestoreInstsAndGetIndex(bbs.getFirst()); + for (BIRNonTerminator ins : bbs.getFirst().instructions.subList(0, instIndex + 1)) { + parentFuncEnv.parentFuncNewInsList.add(ins); + parentFuncEnv.parentFuncLocalVarList.add(ins.lhsOp.variableDcl); + } + parentFuncEnv.returnOperand = arrayIns.lhsOp; BIRVariableDcl handleArray = new BIRVariableDcl(null, symbolTable.handleType, new Name("%listEntryArray"), VarScope.FUNCTION, VarKind.TEMP, null); BIROperand handleArrayOperand = new BIROperand(handleArray); createAndAddNewHandleArrayForLargeArrayIns(parentFuncEnv, arrayIns, handleArray, handleArrayOperand); JLargeArrayInstruction newLargeArrayIns = new JLargeArrayInstruction(arrayIns.pos, - arrayIns.type, arrayIns.lhsOp, arrayIns.typedescOp, arrayIns.sizeOp, handleArrayOperand); + arrayIns.type, arrayIns.lhsOp, arrayIns.typedescOp, arrayIns.elementTypedescOp, arrayIns.sizeOp, + handleArrayOperand); // populating ListConstructorEntry array elements at runtime using jMethodCalls // creating method calls @@ -257,10 +290,6 @@ private void periodicSplitArray(BIRFunction parentFunc, List newlyA List globalAndArgVarIns = getGlobalAndArgVarInsForArray(parentFuncTempVars, arrayIns, handleArrayOperand, birOperands, arrayValuesOperands); - // add the constant load array size operand instruction - parentFuncEnv.parentFuncNewInsList.add(bbs.getFirst().instructions.getFirst()); - parentFuncEnv.parentFuncLocalVarList.add(bbs.getFirst().instructions.getFirst().lhsOp.variableDcl); - splitParentFuncForPeriodicArraySplits(parentFunc, newlyAddingFunctions, fromAttachedFunction, bbs, newArrayInsBBNum, newArrayInsNumInRelevantBB, handleArray, handleArrayOperand, birOperands, splitFuncEnv, parentFuncEnv, arrayValuesOperands); @@ -380,6 +409,83 @@ private void createAndAddNewHandleArrayForLargeMapIns(ParentFuncEnv parentFuncEn parentFuncEnv.parentFuncNewInsList.add(callHandleArray); } + /** + * Create a tuple from the arguments after {@link #MAX_SPLIT_FUNCTION_ARG_COUNT} and replace those arguments + * by the tuple. This is to prevent `to many arguments` error. + * + * eg: + * if {@link #MAX_SPLIT_FUNCTION_ARG_COUNT} = 5 + * before + * %23 = $split$method$_1(%9, %11, %13, %15, %21, %19, %17, %2, %1) -> bb2; + * after + * %argTupleTypeDesc_0 = newType (typeDesc<(int, int, int)>, typeDesc<(int, int, int)>, int, int); + * %argTupleSize = ConstLoad 4; + * %argTuple_0 = newArray %argTupleTypeDesc_0[%argTupleSize]{%19,%17,%2,%1}; + * %23 = $split$method$_1(%9, %11, %13, %15, %21, %argTuple_0) -> bb2; + * + * @param parentFuncLocalVarList local variables of the parent function + * @param splitArgs arguments needs to be passed to the split function + * @param parentFuncNewInsList parent function instructions + * @return newly compressed argument names to the argument tuple + */ + private List createArgTupleAndGetArgNameList(List parentFuncLocalVarList, + List splitArgs, + List parentFuncNewInsList) { + BTypeSymbol tupleTypeSymbol = Symbols.createTypeSymbol(SymTag.TUPLE_TYPE, Flags.asMask(EnumSet.of(Flag.PUBLIC)), + Names.EMPTY, currentPackageId, null, null, null, VIRTUAL); + List argList = new ArrayList<>(splitArgs.subList( + MAX_SPLIT_FUNCTION_ARG_COUNT, splitArgs.size())); + int argSize = argList.size(); + List memberTypes = new ArrayList<>(argSize); + BTupleType tupleType = new BTupleType(tupleTypeSymbol, memberTypes); + tupleTypeSymbol.type = tupleType; + + List initialValues = new ArrayList<>(argSize); + List argNames = new ArrayList<>(argSize); + for (BIRVariableDcl arg : argList) { + // Add arg type as a member type of the tuple type + BVarSymbol varSymbol = new BVarSymbol(0, Names.EMPTY, + currentPackageId, arg.type, null, null, VIRTUAL); + memberTypes.add(new BTupleMember(arg.type, varSymbol)); + + // Add arg as a list constructor member + initialValues.add(new BIRNode.BIRListConstructorExprEntry(new BIROperand(arg))); + argNames.add(arg.name); + } + + // Create new type desc instruction for the tuple type + BIRVariableDcl typeDescVarDecl = new BIRVariableDcl(null, symbolTable.typeDesc, + new Name(ARG_TUPLE_TYPEDESC + argTupleTypeDescIndex++), VarScope.FUNCTION, VarKind.TEMP, null); + parentFuncLocalVarList.add(typeDescVarDecl); + BIROperand typeDescOp = new BIROperand(typeDescVarDecl); + BIRNonTerminator.NewTypeDesc newTypeDesc = new BIRNonTerminator.NewTypeDesc(null, typeDescOp, + tupleType, Collections.emptyList()); + parentFuncNewInsList.add(newTypeDesc); + + // Create a constant load instruction to load the size of the tuple + BIRVariableDcl size = new BIRVariableDcl(null, symbolTable.intType, + new Name(ARG_TUPLE_SIZE), VarScope.FUNCTION, VarKind.TEMP, null); + parentFuncLocalVarList.add(size); + BIROperand sizeOp = new BIROperand(size); + BIRNonTerminator.ConstantLoad sizeLoadInst = new BIRNonTerminator.ConstantLoad(null, + (long) argSize, symbolTable.intType, sizeOp); + parentFuncNewInsList.add(sizeLoadInst); + + // Add new array instruction to create the large argument tuple + BIRVariableDcl largeArgTuple = new BIRVariableDcl(null, tupleType, + new Name(ARG_TUPLE + argTupleIndex++), VarScope.FUNCTION, VarKind.TEMP, null); + parentFuncLocalVarList.add(largeArgTuple); + BIROperand largeArgTupleOperand = new BIROperand(largeArgTuple); + parentFuncNewInsList.add(new BIRNonTerminator.NewArray(null, tupleType, largeArgTupleOperand, + typeDescOp, sizeOp, initialValues)); + + // Replace args of the current split with the large argument tuple + splitArgs.subList(MAX_SPLIT_FUNCTION_ARG_COUNT, splitArgs.size()).clear(); + splitArgs.add(largeArgTuple); + + return argNames; + } + private void createAndAddNewHandleArrayForLargeArrayIns(ParentFuncEnv parentFuncEnv, BIRNonTerminator.NewArray arrayIns, BIRVariableDcl handleArray, BIROperand handleArrayOperand) { @@ -601,10 +707,9 @@ private void splitParentFuncForPeriodicMapSplits(BIRFunction parentFunc, List instructions = bb.instructions; + for (int i = 0; i < instructions.size(); i = i + 2) { + if (!instructions.get(i).lhsOp.variableDcl.name.value.equals(ARG_INDEX)) { + return i; + } + } + return 0; + } + private void handleBBInstructions(SplitFuncEnv splitFuncEnv, BIRBasicBlock bb) { splitFuncEnv.splitFuncBB.instructions = splitFuncEnv.splitFuncNewInsList; splitFuncEnv.splitFuncBB.terminator = bb.terminator; @@ -794,6 +916,29 @@ private void createNewFuncForPeriodicSplit(BIRFunction parentFunc, List MAX_SPLIT_FUNCTION_ARG_COUNT) { + List newFuncArgs = new ArrayList<>(splitFuncEnv.splitFuncArgs); + List parentFuncLocalVars = new ArrayList<>(parentFuncEnv.parentFuncLocalVarList); + + List argNameList = createArgTupleAndGetArgNameList( + parentFuncLocalVars, newFuncArgs, parentFuncEnv.parentFuncNewInsList); + + splitFuncEnv.splitFuncArgs = new LinkedHashSet<>(newFuncArgs); + parentFuncEnv.parentFuncLocalVarList = new LinkedHashSet<>(parentFuncLocalVars); + + List splitFuncLocalVarList = new ArrayList<>(splitFuncEnv.splitFuncLocalVarList); + List argRestoreInstructions = new ArrayList<>(); + + restoreOriginalArgsFromTuple(argNameList, newFuncArgs, splitFuncLocalVarList, argRestoreInstructions); + + splitFuncEnv.splitFuncLocalVarList = new LinkedHashSet<>(splitFuncLocalVarList); + if (splitFuncEnv.splitFuncNewBBList.size() > 0) { + splitFuncEnv.splitFuncNewBBList.getFirst().instructions.addAll(0, argRestoreInstructions); + } else { + splitFuncEnv.splitFuncNewInsList.addAll(0, argRestoreInstructions); + } + } + // Create a new split BIRFunction List paramTypes = new ArrayList<>(); for (BIRVariableDcl funcArg : splitFuncEnv.splitFuncArgs) { @@ -1184,8 +1329,8 @@ private List getPossibleSplits(List basicBlocks, List neededOperandsVarDcl = new HashSet<>(); // that will need to be passed as function args - Set lhsOperandList = new HashSet<>(); // that will need as localVars in the new function + Set neededOperandsVarDcl = new LinkedHashSet<>(); // that will need to be passed as func args + Set lhsOperandList = new LinkedHashSet<>(); // that will need as localVars in the new function BIROperand splitStartOperand = null; int splitInsCount = 0; // including terminator instructions @@ -1241,9 +1386,8 @@ private List getPossibleSplits(List basicBlocks, List MAX_SPLIT_FUNCTION_ARG_COUNT) || - (splitInsCount < SPLIT_INSTRUCTION_COUNT_THRESHOLD)) { + if (currIns.lhsOp.variableDcl == splitStartOperand.variableDcl) { + if (splitInsCount < SPLIT_INSTRUCTION_COUNT_THRESHOLD) { splitStarted = false; continue; } @@ -1274,34 +1418,59 @@ private List getPossibleSplits(List basicBlocks, List startOfStructInst = new ArrayList<>(); if (currIns.kind == InstructionKind.NEW_ARRAY) { BIRNonTerminator.NewArray arrayIns = (BIRNonTerminator.NewArray) currIns; splitStartOperand = arrayIns.sizeOp; + Optional.ofNullable(arrayIns.typedescOp).ifPresent(startOfStructInst::add); + Optional.ofNullable(arrayIns.elementTypedescOp).ifPresent(startOfStructInst::add); splitTypeArray = true; } else { BIRNonTerminator.NewStructure structureIns = (BIRNonTerminator.NewStructure) currIns; - splitStartOperand = structureIns.rhsOp; + if (structureIns.initialValues.size() == 0) { + continue; + } + + startOfStructInst.add(structureIns.rhsOp); + BIRNode.BIRMappingConstructorEntry firstInitialValue = structureIns.initialValues.get(0); + if (firstInitialValue.isKeyValuePair()) { + BIRNode.BIRMappingConstructorKeyValueEntry keyValueEntry = + (BIRNode.BIRMappingConstructorKeyValueEntry) firstInitialValue; + splitStartOperand = keyValueEntry.keyOp; + } else { + BIRNode.BIRMappingConstructorSpreadFieldEntry exprEntry = + (BIRNode.BIRMappingConstructorSpreadFieldEntry) firstInitialValue; + splitStartOperand = exprEntry.exprOp; + } + splitTypeArray = false; } + startOfStructInst.add(splitStartOperand); // if the split will have all the available instructions already in the function - // no need to make that split, avoids doing the same split repeatedly if ((bbNum == basicBlocks.size() - 2) && (!basicBlocks.getFirst().instructions.isEmpty()) && - (basicBlocks.getFirst().instructions.getFirst().lhsOp == splitStartOperand) - && fromSplitFunction) { - continue; + fromSplitFunction) { + List firstBBIns = basicBlocks.getFirst().instructions; + BIRNonTerminator firstIns = firstBBIns.get( + skipLargeArgRestoreInstsAndGetIndex(basicBlocks.getFirst())); + if (((startOfStructInst.stream().map(op -> op.variableDcl).toList().contains( + firstIns.lhsOp.variableDcl)))) { + continue; + } } splitStarted = true; returnValAssigned = false; - neededOperandsVarDcl = new HashSet<>(); + neededOperandsVarDcl = new LinkedHashSet<>(); BIROperand[] initialRhsOperands = currIns.getRhsOperands(); for (BIROperand rhsOperand : initialRhsOperands) { if (needToPassRhsVarDclAsArg(rhsOperand)) { neededOperandsVarDcl.add(rhsOperand.variableDcl); } } - lhsOperandList = new HashSet<>(); + lhsOperandList = new LinkedHashSet<>(); splitInsCount = 1; splitEndInsIndex = insNum; splitEndBBIndex = bbNum; @@ -1449,8 +1618,11 @@ private void generateSplits(BIRFunction function, List possibleSplits, } // extra +1 for BB incremented in createNewBIRFunctionAcrossBB function, hence BB number is newBBNum + 2 BIRBasicBlock parentFuncNewBB = new BIRBasicBlock(newBBNum + 2); + boolean largeArgs = currSplit.funcArgs.size() > MAX_SPLIT_FUNCTION_ARG_COUNT; + List argNameList = largeArgs ? createArgTupleAndGetArgNameList(function.localVars, + currSplit.funcArgs, currentBB.instructions) : new ArrayList<>(); BIRFunction newBIRFunc = createNewBIRFunctionAcrossBB(function, newFuncName, newFuncReturnType, currSplit, - newBBNum, fromAttachedFunction, changedErrorTableEndBB, parentFuncNewBB); + newBBNum, fromAttachedFunction, changedErrorTableEndBB, parentFuncNewBB, argNameList); newBBNum += 2; newlyAddedFunctions.add(newBIRFunc); if (currSplit.splitFurther) { @@ -1654,12 +1826,13 @@ private void setLocalVarStartEndBB(BIRFunction birFunction, List * @param fromAttachedFunction flag which indicates an original attached function is being split * @param changedErrorTableEndBB changed error table end basic block map * @param parentFuncNewBB parent function new BB + * @param argNameList if split function has large number of arguments, this will contain the arg names * @return newly created BIR function */ private BIRFunction createNewBIRFunctionAcrossBB(BIRFunction parentFunc, Name funcName, BType retType, Split currSplit, int newBBNum, boolean fromAttachedFunction, Map changedErrorTableEndBB, - BIRBasicBlock parentFuncNewBB) { + BIRBasicBlock parentFuncNewBB, List argNameList) { List parentFuncBBs = parentFunc.basicBlocks; BIRNonTerminator lastIns = parentFuncBBs.get(currSplit.endBBNum).instructions.get(currSplit.lastIns); List paramTypes = new ArrayList<>(); @@ -1700,6 +1873,7 @@ private BIRFunction createNewBIRFunctionAcrossBB(BIRFunction parentFunc, Name fu // creates BBs BIRBasicBlock entryBB = new BIRBasicBlock(0); + restoreOriginalArgsFromTuple(argNameList, currSplit.funcArgs, birFunc.localVars, entryBB.instructions); if (currSplit.firstIns < parentFuncBBs.get(currSplit.startBBNum).instructions.size()) { entryBB.instructions.addAll(parentFuncBBs.get(currSplit.startBBNum).instructions.subList( currSplit.firstIns, parentFuncBBs.get(currSplit.startBBNum).instructions.size())); @@ -1740,6 +1914,46 @@ private BIRFunction createNewBIRFunctionAcrossBB(BIRFunction parentFunc, Name fu return birFunc; } + /** + * Restore the original arguments if we compress them to single tuple due to large number of arguments. + * + * @param argNameList if split function has large number of arguments, this will contain the arg names to restore + * @param funcArgs split function args + * @param splitFuncLocalVars local var list of the newly created split function + * @param entryBBInstList instruction list of the first BB of the split function + */ + private void restoreOriginalArgsFromTuple(List argNameList, List funcArgs, + List splitFuncLocalVars, + List entryBBInstList) { + if (!argNameList.isEmpty()) { + BIRVariableDcl argTuple = funcArgs.get(funcArgs.size() - 1); + List argTupleMembers = ((BTupleType) argTuple.type).getTupleTypes(); + + // Create temp var to store the arg index which needs to be loaded from the arg tuple + BIRVariableDcl argIndex = new BIRVariableDcl(null, symbolTable.intType, new Name(ARG_INDEX), + VarScope.FUNCTION, VarKind.TEMP, null); + BIROperand argIndexOp = new BIROperand(argIndex); + splitFuncLocalVars.add(argIndex); + for (int i = 0; i < argNameList.size(); i++) { + Name argName = argNameList.get(i); + // Load the current arg index to the `argIndexOp` + BIRNonTerminator.ConstantLoad loadArgNameInst = new BIRNonTerminator.ConstantLoad(null, + (long) i, symbolTable.intType, argIndexOp); + entryBBInstList.add(loadArgNameInst); + + // Create temp var with the original name to store the actual arg + BIRVariableDcl arg = new BIRVariableDcl(null, argTupleMembers.get(i), argName, + VarScope.FUNCTION, VarKind.TEMP, argName.getValue()); + BIROperand argOp = new BIROperand(arg); + splitFuncLocalVars.add(arg); + + BIRNonTerminator.FieldAccess fieldAccess = new BIRNonTerminator.FieldAccess(null, + InstructionKind.ARRAY_LOAD, argOp, argIndexOp, new BIROperand(argTuple)); + entryBBInstList.add(fieldAccess); + } + } + } + private void fixTerminatorBBs(int lastBBIdNum, BIRBasicBlock lastBB, BIRTerminator terminator) { if (terminator.thenBB != null && terminator.thenBB.number == lastBBIdNum) { terminator.thenBB = lastBB; @@ -1790,16 +2004,21 @@ private BIRBasicBlock generateSplitsInSameBB(BIRFunction function, int bbNum, Li Name newFuncName = new Name(newFunctionName); BIROperand currentBBTerminatorLhsOp = new BIROperand(instructionList.get(possibleSplit.lastIns).lhsOp.variableDcl); + currentBB.instructions.addAll(instructionList.subList(startInsNum, possibleSplit.firstIns)); + + boolean largeArgs = possibleSplit.funcArgs.size() > MAX_SPLIT_FUNCTION_ARG_COUNT; + List argNameList = largeArgs ? createArgTupleAndGetArgNameList(function.localVars, + possibleSplit.funcArgs, currentBB.instructions) : new ArrayList<>(); BIRFunction newBIRFunc = createNewBIRFuncForSplitInBB(newFuncName, instructionList.get(possibleSplit.lastIns), instructionList.subList(possibleSplit.firstIns, possibleSplit.lastIns), - possibleSplit.lhsVars, possibleSplit.funcArgs, fromAttachedFunction); + possibleSplit.lhsVars, possibleSplit.funcArgs, fromAttachedFunction, argNameList); newlyAddedFunctions.add(newBIRFunc); if (possibleSplit.splitFurther) { newlyAddedFunctions.addAll(splitBIRFunction(newBIRFunc, fromAttachedFunction, true, possibleSplit.splitTypeArray)); } - currentBB.instructions.addAll(instructionList.subList(startInsNum, possibleSplit.firstIns)); + startInsNum = possibleSplit.lastIns + 1; newBBNum += 1; BIRBasicBlock newBB = new BIRBasicBlock(newBBNum); @@ -1863,7 +2082,7 @@ private BIROperand generateTempLocalVariable(BType variableType, Set collectedIns, Set lhsOperandList, List funcArgs, - boolean fromAttachedFunction) { + boolean fromAttachedFunction, List argNameList) { BType retType = currentIns.lhsOp.variableDcl.type; List paramTypes = new ArrayList<>(); for (BIRVariableDcl funcArg : funcArgs) { @@ -1902,6 +2121,7 @@ private BIRFunction createNewBIRFuncForSplitInBB(Name funcName, BIRNonTerminator // creates 2 bbs BIRBasicBlock entryBB = new BIRBasicBlock(0); + restoreOriginalArgsFromTuple(argNameList, funcArgs, birFunc.localVars, entryBB.instructions); entryBB.instructions.addAll(collectedIns); currentIns.lhsOp = new BIROperand(birFunc.returnVariable); entryBB.instructions.add(currentIns); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/types/JvmRecordTypeGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/types/JvmRecordTypeGen.java index 0523a64c5ce7..df5a66459a82 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/types/JvmRecordTypeGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/types/JvmRecordTypeGen.java @@ -23,7 +23,6 @@ import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.BallerinaClassWriter; import org.wso2.ballerinalang.compiler.bir.codegen.JarEntries; -import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.JvmPackageGen; import org.wso2.ballerinalang.compiler.bir.codegen.JvmTypeGen; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; @@ -39,21 +38,16 @@ import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_SUPER; -import static org.objectweb.asm.Opcodes.ACONST_NULL; import static org.objectweb.asm.Opcodes.CHECKCAST; import static org.objectweb.asm.Opcodes.DUP; -import static org.objectweb.asm.Opcodes.DUP_X1; import static org.objectweb.asm.Opcodes.GETSTATIC; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.NEW; import static org.objectweb.asm.Opcodes.PUTFIELD; -import static org.objectweb.asm.Opcodes.PUTSTATIC; -import static org.objectweb.asm.Opcodes.SWAP; import static org.objectweb.asm.Opcodes.V21; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.getModuleLevelClassName; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.toNameString; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CLASS_FILE_SUFFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LINKED_HASH_MAP; @@ -62,13 +56,10 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RECORD_TYPE_IMPL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MODULE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_TYPE; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_TYPEDESC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.RECORD_TYPE_IMPL_INIT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SET_LINKED_HASH_MAP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SET_MAP; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.TYPE_DESC_CONSTRUCTOR; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.VOID_METHOD_DESC; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmValueGen.getTypeDescClassName; /** * BIR record type to JVM byte code generation class. @@ -176,16 +167,6 @@ public void createRecordType(MethodVisitor mv, BRecordType recordType, String ty // initialize the record type mv.visitMethodInsn(INVOKESPECIAL, RECORD_TYPE_IMPL, JVM_INIT_METHOD, RECORD_TYPE_IMPL_INIT, false); - - mv.visitInsn(DUP); - String packageName = JvmCodeGenUtil.getPackageName(recordType.tsymbol.pkgID); - String className = getTypeDescClassName(packageName, toNameString(recordType)); - mv.visitTypeInsn(NEW, className); - mv.visitInsn(DUP_X1); - mv.visitInsn(SWAP); - mv.visitInsn(ACONST_NULL); - mv.visitMethodInsn(INVOKESPECIAL, className, JVM_INIT_METHOD, TYPE_DESC_CONSTRUCTOR, false); - mv.visitFieldInsn(PUTSTATIC, typeOwnerClass, jvmTypeGen.getTypedescFieldName(internalName), GET_TYPEDESC); } private String getFullName(BRecordType recordType) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/emit/InstructionEmitter.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/emit/InstructionEmitter.java index 66aa82d80495..f15666c150a5 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/emit/InstructionEmitter.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/emit/InstructionEmitter.java @@ -245,6 +245,9 @@ private static String emitInsNewArray(BIRNonTerminator.NewArray ins, int tabs) { str += "["; str += emitVarRef(ins.sizeOp); str += "]"; + if (ins.elementTypedescOp != null) { + str += " elementTypeDesc " + emitVarRef(ins.elementTypedescOp); + } str += "{"; str += emitArrayValues(ins.values); str += "}"; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNode.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNode.java index c6a880d0031b..109858a0dd13 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNode.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNode.java @@ -146,6 +146,7 @@ public static class BIRVariableDcl extends BIRDocumentableNode { public BIRBasicBlock startBB; public int insOffset; public boolean onlyUsedInSingleBB; + public boolean initialized = false; // Stores the scope of the current instruction with respect to local variables. public BirScope insScope; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNonTerminator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNonTerminator.java index 6db23cbed853..d5978a2dc9bf 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNonTerminator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/model/BIRNonTerminator.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; import static org.wso2.ballerinalang.compiler.bir.model.InstructionKind.RECORD_DEFAULT_FP_LOAD; @@ -56,6 +57,7 @@ public Move(Location pos, BIROperand fromOperand, BIROperand toOperand) { super(pos, InstructionKind.MOVE); this.rhsOp = fromOperand; this.lhsOp = toOperand; + toOperand.variableDcl.initialized = true; } @Override @@ -210,13 +212,6 @@ public static class NewStructure extends BIRNonTerminator { public BIROperand rhsOp; public List initialValues; - public NewStructure(Location pos, BIROperand lhsOp, BIROperand rhsOp) { - super(pos, InstructionKind.NEW_STRUCTURE); - this.lhsOp = lhsOp; - this.rhsOp = rhsOp; - this.initialValues = new ArrayList<>(); - } - public NewStructure(Location pos, BIROperand lhsOp, BIROperand rhsOp, List initialValues) { super(pos, InstructionKind.NEW_STRUCTURE); @@ -324,6 +319,7 @@ public void setRhsOperands(BIROperand[] operands) { */ public static class NewArray extends BIRNonTerminator { public BIROperand typedescOp; + public BIROperand elementTypedescOp; public BIROperand sizeOp; public BType type; public List values; @@ -350,19 +346,15 @@ public void accept(BIRVisitor visitor) { @Override public BIROperand[] getRhsOperands() { - int i = 0; - BIROperand[] operands; - if (typedescOp != null) { - operands = new BIROperand[values.size() + 2]; - operands[i++] = typedescOp; - } else { - operands = new BIROperand[values.size() + 1]; - } - operands[i++] = sizeOp; + List operands = new ArrayList<>(); + Optional.ofNullable(typedescOp).ifPresent(operands::add); + Optional.ofNullable(elementTypedescOp).ifPresent(operands::add); + operands.add(sizeOp); for (BIRListConstructorEntry listValueEntry : values) { - operands[i++] = listValueEntry.exprOp; + operands.add(listValueEntry.exprOp); } - return operands; + + return operands.toArray(new BIROperand[0]); } @Override @@ -371,6 +363,9 @@ public void setRhsOperands(BIROperand[] operands) { if (typedescOp != null) { typedescOp = operands[i++]; } + if (elementTypedescOp != null) { + elementTypedescOp = operands[i++]; + } sizeOp = operands[i++]; for (BIRListConstructorEntry listValueEntry : values) { listValueEntry.exprOp = operands[i++]; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIROptimizer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIROptimizer.java index 61a755adf31f..4a21a7710538 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIROptimizer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIROptimizer.java @@ -347,6 +347,9 @@ private void replaceVarsWithReusableVars(List localVars, List reusableList = typeVsReusableVarsMap.get(variableDcl.type); + if (reusableList == null) { + continue; + } // Same var can be used by multiple operands. We need to collect all and then replace them with // variable declarations. if (reusableVar != null) { @@ -562,6 +565,7 @@ public void visit(BIRNonTerminator.NewArray birNewArray) { if (birNewArray.typedescOp != null) { birNewArray.typedescOp.accept(this); } + this.optimizeNode(birNewArray.elementTypedescOp, this.env); } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIRRecordValueOptimizer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIRRecordValueOptimizer.java index 5b1f5c0e8e7d..9395d8d519fa 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIRRecordValueOptimizer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/optimizer/BIRRecordValueOptimizer.java @@ -26,21 +26,17 @@ import org.wso2.ballerinalang.compiler.bir.model.InstructionKind; import org.wso2.ballerinalang.compiler.bir.model.VarKind; import org.wso2.ballerinalang.compiler.bir.model.VarScope; -import org.wso2.ballerinalang.compiler.semantics.analyzer.Types; -import org.wso2.ballerinalang.compiler.semantics.model.types.BRecordType; -import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.util.Name; -import org.wso2.ballerinalang.compiler.util.TypeTags; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import static org.wso2.ballerinalang.compiler.bir.model.InstructionKind.CONST_LOAD; import static org.wso2.ballerinalang.compiler.bir.model.InstructionKind.FP_CALL; import static org.wso2.ballerinalang.compiler.bir.model.InstructionKind.TYPE_CAST; +import static org.wso2.ballerinalang.compiler.util.Constants.RECORD_DELIMITER; /** * Remove redundant default function calls for record value creation. @@ -49,9 +45,6 @@ */ public class BIRRecordValueOptimizer extends BIRVisitor { - private final List recordOperandList = new ArrayList<>(); - private final Map recordOperandTypeMap = new HashMap<>(); - private BIRNode.BIRBasicBlock lastBB = null; private BIRNode.BIRFunction currentFunction = null; private List newBBs = new ArrayList<>(); @@ -90,10 +83,9 @@ public void visit(BIRNode.BIRFunction birFunction) { public void visit(BIRNode.BIRBasicBlock basicBlock) { List instructions = basicBlock.instructions; for (BIRNonTerminator inst : instructions) { - if (Objects.requireNonNull(inst.kind) == InstructionKind.NEW_TYPEDESC) { - handleNewTypeDesc(inst); - } else if (inst.kind == InstructionKind.NEW_STRUCTURE) { - handleNewStructure((BIRNonTerminator.NewStructure) inst); + if (inst.kind == InstructionKind.NEW_STRUCTURE) { + valueCreated = true; + break; } } if (!fpRemoved) { @@ -111,16 +103,8 @@ public void visit(BIRNode.BIRBasicBlock basicBlock) { private void handleFPCall(BIRNode.BIRBasicBlock basicBlock) { BIRTerminator.FPCall fpCall = (BIRTerminator.FPCall) basicBlock.terminator; - BIROperand recOperand = recordOperandList.isEmpty() ? null : - recordOperandList.get(recordOperandList.size() - 1); - BRecordType recordType = recordOperandTypeMap.get(recOperand); - - if (recordType == null || recordType.tsymbol == null) { - resetBasicBlock(basicBlock); - return; - } - if (!fpCall.fp.variableDcl.name.value.contains(recordType.tsymbol.name.value)) { + if (!fpCall.fp.variableDcl.name.value.contains(RECORD_DELIMITER)) { resetBasicBlock(basicBlock); return; } @@ -143,19 +127,6 @@ private void handleFPCall(BIRNode.BIRBasicBlock basicBlock) { } } - private void handleNewStructure(BIRNonTerminator.NewStructure inst) { - recordOperandList.remove(inst.rhsOp); - valueCreated = true; - } - - private void handleNewTypeDesc(BIRNonTerminator inst) { - BType referredType = Types.getReferredType(((BIRNonTerminator.NewTypeDesc) inst).type); - if (referredType.tag == TypeTags.RECORD) { - recordOperandList.add(inst.lhsOp); - recordOperandTypeMap.put(inst.lhsOp, (BRecordType) referredType); - } - } - private void moveConstLoadInstruction(BIRTerminator.FPCall fpCall, BIRNode.BIRBasicBlock firstBB) { BIRNonTerminator.ConstantLoad constantLoad = (BIRNonTerminator.ConstantLoad) firstBB.instructions.get(0); if (firstBB.instructions.size() == 2) { @@ -196,8 +167,10 @@ private boolean containsOnlyConstantLoad(BIRNode.BIRFunction defaultFunction) { return false; } return switch (firstBB.instructions.size()) { - case 1 -> firstBB.instructions.get(0).kind == CONST_LOAD; - case 2 -> firstBB.instructions.get(0).kind == CONST_LOAD && firstBB.instructions.get(1).kind == TYPE_CAST; + case 1 -> firstBB.instructions.get(0).kind == CONST_LOAD && firstBB.instructions.get(0).lhsOp.variableDcl + .kind == VarKind.RETURN; + case 2 -> firstBB.instructions.get(0).kind == CONST_LOAD && firstBB.instructions.get(1).kind == TYPE_CAST + && firstBB.instructions.get(1).lhsOp.variableDcl.kind == VarKind.RETURN; default -> false; }; } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/writer/BIRInstructionWriter.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/writer/BIRInstructionWriter.java index 2cbaefc233ac..e2fc901eab21 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/writer/BIRInstructionWriter.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/writer/BIRInstructionWriter.java @@ -444,6 +444,12 @@ public void visit(NewArray birNewArray) { } else { buf.writeByte(0); } + if (birNewArray.elementTypedescOp != null) { + buf.writeByte(1); + birNewArray.elementTypedescOp.accept(this); + } else { + buf.writeByte(0); + } birNewArray.sizeOp.accept(this); buf.writeInt(birNewArray.values.size()); for (BIRNode.BIRListConstructorEntry listValueEntry : birNewArray.values) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java index 5d091d631269..763713b1cb02 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java @@ -24,6 +24,7 @@ import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.symbols.SymbolKind; import org.ballerinalang.model.tree.NodeKind; +import org.ballerinalang.model.tree.TopLevelNode; import org.ballerinalang.model.tree.expressions.RecordLiteralNode; import org.wso2.ballerinalang.compiler.semantics.analyzer.SymbolResolver; import org.wso2.ballerinalang.compiler.semantics.analyzer.Types; @@ -206,6 +207,7 @@ import org.wso2.ballerinalang.util.Flags; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -271,7 +273,7 @@ public void visit(BLangPackage pkgNode) { pkgNode.constants.forEach(constant -> rewrite(constant, pkgEnv)); pkgNode.annotations.forEach(annotation -> rewrite(annotation, pkgEnv)); pkgNode.initFunction = rewrite(pkgNode.initFunction, pkgEnv); - pkgNode.classDefinitions = rewrite(pkgNode.classDefinitions, pkgEnv); + rewrite(pkgNode.classDefinitions, pkgEnv); rewrite(pkgNode.globalVars, pkgEnv); addClosuresToGlobalVariableList(pkgEnv); for (int i = 0; i < pkgNode.functions.size(); i++) { @@ -291,9 +293,12 @@ private void addClosuresToGlobalVariableList(SymbolEnv pkgEnv) { simpleVariable.flagSet.add(Flag.PUBLIC); simpleVariable.symbol.flags |= Flags.PUBLIC; pkgEnv.enclPkg.globalVars.add(0, simpleVariable); + pkgEnv.enclPkg.topLevelNodes.add(0, simpleVariable); } for (BLangSimpleVariableDef closureReference : annotationClosureReferences) { - pkgEnv.enclPkg.globalVars.add(rewrite(closureReference.var, pkgEnv)); + BLangSimpleVariable simpleVariable = rewrite(closureReference.var, pkgEnv); + pkgEnv.enclPkg.globalVars.add(simpleVariable); + pkgEnv.enclPkg.topLevelNodes.add(simpleVariable); } } @@ -1813,9 +1818,15 @@ private List rewrite(List nodeList, SymbolEnv env) { for (int i = 0; i < size; i++) { E node = rewrite(nodeList.remove(0), env); Iterator iterator = annotationClosureReferences.iterator(); + List closureList = new ArrayList<>(); while (iterator.hasNext()) { - nodeList.add(rewrite((E) annotationClosureReferences.poll().var, env)); + E simpleVariable = rewrite((E) annotationClosureReferences.poll().var, env); + closureList.add(simpleVariable); } + // Add closures before the dependent node in the top-level node list + int indexAtTopLevel = env.enclPkg.topLevelNodes.indexOf(node); + env.enclPkg.topLevelNodes.addAll(indexAtTopLevel, (Collection) closureList); + nodeList.addAll(closureList); nodeList.add(node); } this.annotationClosureReferences = previousQueue; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java index 049701b1cd49..6d9554442760 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java @@ -62,6 +62,7 @@ import org.wso2.ballerinalang.compiler.semantics.model.symbols.BResourceFunction; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BResourcePathSegmentSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.BTypeDefinitionSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BTypeSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BVarSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BXMLNSSymbol; @@ -81,6 +82,7 @@ import org.wso2.ballerinalang.compiler.semantics.model.types.BTupleMember; import org.wso2.ballerinalang.compiler.semantics.model.types.BTupleType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; +import org.wso2.ballerinalang.compiler.semantics.model.types.BTypeReferenceType; import org.wso2.ballerinalang.compiler.semantics.model.types.BTypedescType; import org.wso2.ballerinalang.compiler.semantics.model.types.BUnionType; import org.wso2.ballerinalang.compiler.semantics.model.types.BXMLSubType; @@ -317,7 +319,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; @@ -371,6 +372,7 @@ public class Desugar extends BLangNodeVisitor { private static final String PUSH_LANGLIB_METHOD = "push"; private static final String DESUGARED_VARARG_KEY = "$vararg$"; private static final String GENERATED_ERROR_VAR = "$error$"; + private static final String TYPEDESC = "$typedesc$"; private static final String HAS_KEY = "hasKey"; private static final String CREATE_RECORD_VALUE = "createRecordFromMap"; private static final String CHANNEL_AUTO_CLOSE_FUNC_NAME = "autoClose"; @@ -413,6 +415,7 @@ public class Desugar extends BLangNodeVisitor { private final List enclosingOnFailClause = new ArrayList<>(); private final Map enclosingShouldPanic = new HashMap<>(); private final List enclosingShouldContinue = new ArrayList<>(); + private List typedescList = new ArrayList<>(); private BLangSimpleVarRef shouldRetryRef; private SymbolEnv env; @@ -426,6 +429,7 @@ public class Desugar extends BLangNodeVisitor { private int funcParamCount = 1; private boolean isVisitingQuery; private boolean desugarToReturn; + private int typedescCount = 0; // Worker related variables private Set channelsWithinIfStmt = new LinkedHashSet<>(); @@ -790,37 +794,31 @@ public void visit(BLangPackage pkgNode) { // Initialize the annotation map annotationDesugar.initializeAnnotationMap(pkgNode); - pkgNode.constants.stream() - .filter(constant -> (constant.expr.getKind() == NodeKind.LITERAL || - constant.expr.getKind() == NodeKind.NUMERIC_LITERAL) - && constant.expr.getBType().tag != TypeTags.TUPLE) - .forEach(constant -> pkgNode.typeDefinitions.add(constant.associatedTypeDefinition)); - - BLangBlockStmt serviceAttachments = serviceDesugar.rewriteServiceVariables(pkgNode.services, env); - BLangBlockFunctionBody initFnBody = (BLangBlockFunctionBody) pkgNode.initFunction.body; - - rewriteConstants(pkgNode, initFnBody); - pkgNode.constants = removeDuplicateConstants(pkgNode); + for (BLangConstant constant : pkgNode.constants) { + if ((constant.expr.getKind() == NodeKind.LITERAL || + constant.expr.getKind() == NodeKind.NUMERIC_LITERAL) + && constant.expr.getBType().tag != TypeTags.TUPLE) { + pkgNode.typeDefinitions.add(constant.associatedTypeDefinition); + } + } - pkgNode.globalVars = desugarGlobalVariables(pkgNode, initFnBody); - + BLangBlockStmt serviceAttachments = serviceDesugar.rewriteServiceVariables(pkgNode.services, env); pkgNode.services.forEach(service -> serviceDesugar.engageCustomServiceDesugar(service, env)); + // Desugar variables, constants and type definitions. + desugarTopLevelNodes(pkgNode); + annotationDesugar.rewritePackageAnnotations(pkgNode, env); + rewrite(pkgNode.xmlnsList, env); + rewrite(pkgNode.constants, env); + rewrite(pkgNode.globalVars, env); + rewrite(pkgNode.classDefinitions, env); + // Add invocation for user specified module init function (`init()`) if present and return. addUserDefinedModuleInitInvocationAndReturn(pkgNode); - //Sort type definitions with precedence - pkgNode.typeDefinitions.sort(Comparator.comparing(t -> t.precedence)); - - pkgNode.typeDefinitions = rewrite(pkgNode.typeDefinitions, env); - pkgNode.xmlnsList = rewrite(pkgNode.xmlnsList, env); - pkgNode.constants = rewrite(pkgNode.constants, env); - pkgNode.globalVars = rewrite(pkgNode.globalVars, env); - pkgNode.classDefinitions = rewrite(pkgNode.classDefinitions, env); - serviceDesugar.rewriteListeners(pkgNode.globalVars, env, pkgNode.startFunction, pkgNode.stopFunction); ASTBuilderUtil.appendStatements(serviceAttachments, (BLangBlockFunctionBody) pkgNode.initFunction.body); @@ -853,35 +851,97 @@ public void visit(BLangPackage pkgNode) { rewrite(testablePkg, this.symTable.pkgEnvMap.get(testablePkg.symbol)); } pkgNode.completedPhases.add(CompilerPhase.DESUGAR); + clearGlobalVariables(); + result = pkgNode; } - private void rewriteConstants(BLangPackage pkgNode, BLangBlockFunctionBody initFnBody) { - for (BLangConstant constant : pkgNode.constants) { - BType constType = Types.getReferredType(constant.symbol.type); - if (constType.tag != TypeTags.INTERSECTION) { - continue; + private void desugarConstants(BLangConstant constant, List desugaredGlobalVarList, + BLangBlockFunctionBody initFnBody, SymbolEnv initFunctionEnv) { + BType constType = Types.getReferredType(constant.symbol.type); + if (constType.tag != TypeTags.INTERSECTION) { + return; + } + + BConstantSymbol constSymbol = constant.symbol; + BType impliedType = Types.getImpliedType(constSymbol.literalType); + int tag = impliedType.tag; + if (((tag == TypeTags.RECORD || tag == TypeTags.MAP) && constant.expr.getKind() == NodeKind.RECORD_LITERAL_EXPR) + || (tag == TypeTags.TUPLE && constant.expr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR)) { + // Literal type will have a typedesc var created via the associated type def. + // The issue is that type def has the effective type not the original intersection. + // Hence, create the typedesc var here. + // Todo: In the below sample, `a` and `b` will have the same literal type. Then the typedesc will be + // created with the same type. ATM in the BIRGen we lookup the typedesc given the type. Hence that + // logic will fail to identify the correct typedesc and it will fail when there are large methods. + // Need to find a fix for this. ATM we create only one typedesc for the + // following sample to overcome that issue. + // + // const string[] a = ["apple", "orange"]; + // const string[] b = a; + BLangType blangIntersection = (BLangIntersectionTypeNode) TreeBuilder.createIntersectionTypeNode(); + blangIntersection.setBType(constSymbol.literalType); + blangIntersection.pos = constSymbol.literalType.tsymbol.pos; + createTypedescVariableForAnonType(blangIntersection); + } + + addTypeDescStmtsToInitFunction(initFunctionEnv, desugaredGlobalVarList, initFnBody); + BLangSimpleVarRef constVarRef = ASTBuilderUtil.createVariableRef(constant.pos, constant.symbol); + BLangAssignment constInit = ASTBuilderUtil.createAssignmentStmt(constant.pos, constVarRef, constant.expr); + initFnBody.stmts.add(constInit); + constant.expr = null; + } + + private void createTypedescVariable(BType type, Location pos) { + BType finalType = type; + if ((Types.getReferredType(type).tag != TypeTags.INTERSECTION && this.env.enclPkg.typeDefinitions.stream() + .anyMatch(typeDef -> + (Types.getReferredType(typeDef.typeNode.getBType()).tag == TypeTags.INTERSECTION) && + typeDef.symbol.name.value.equals(finalType.tsymbol.name.value)))) { + // This is a workaround for an issue where we create two type defs with same name for the below sample + // type T1 [T1] & readonly; + return; + } + + Name name = generateTypedescVariableName(type); + if (type.tag == TypeTags.TYPEREFDESC) { + BType referredType = ((BTypeReferenceType) type).referredType; + int tag = referredType.tag; + if (tag == TypeTags.RECORD) { + type = referredType; } - for (BType memberType : ((BIntersectionType) constType).getConstituentTypes()) { - BLangType typeNode; - switch (Types.getImpliedType(memberType).tag) { - case TypeTags.RECORD: - typeNode = constant.associatedTypeDefinition.typeNode; - break; - case TypeTags.TUPLE: - typeNode = (BLangTupleTypeNode) TreeBuilder.createTupleTypeNode(); - break; - default: - continue; - } - BLangSimpleVarRef constVarRef = ASTBuilderUtil.createVariableRef(constant.pos, constant.symbol); - constant.expr = rewrite(constant.expr, - SymbolEnv.createTypeEnv(typeNode, pkgNode.initFunction.symbol.scope, env)); - BLangAssignment constInit = ASTBuilderUtil.createAssignmentStmt(constant.pos, constVarRef, - constant.expr); - initFnBody.stmts.add(constInit); + } + BType typedescType = new BTypedescType(type, symTable.typeDesc.tsymbol); + BSymbol owner = this.env.scope.owner; + BVarSymbol varSymbol = new BVarSymbol(0, name, owner.pkgID, typedescType, owner, pos, VIRTUAL); + BLangTypedescExpr typedescExpr = ASTBuilderUtil.createTypedescExpr(pos, typedescType, type); + typedescList.add(createSimpleVariableDef(pos, name.value, typedescType, typedescExpr, varSymbol)); + } + + private void createTypedescVariableForAnonType(BLangType typeNode) { + BLangNode parentNode = typeNode.parent; + if (parentNode != null && parentNode.getKind() == NodeKind.TYPE_DEFINITION) { + BSymbol typeDefSymbol = ((BLangTypeDefinition) parentNode).symbol; + if (typeDefSymbol.kind == SymbolKind.TYPE_DEF && typeDefSymbol.origin != VIRTUAL) { + return; } } + createTypedescVariable(typeNode.getBType(), typeNode.pos); + } + + private Name generateTypedescVariableName(BType targetType) { + // tsymbol.name.value is empty for anonymous types except for record types and map types + return targetType.tag == TypeTags.MAP || targetType.tsymbol.name.value.isEmpty() ? + new Name(TYPEDESC + typedescCount++) : new Name(TYPEDESC + targetType.tsymbol.name.value); + } + + private BLangSimpleVariableDef createSimpleVariableDef(Location pos, String name, BType type, BLangExpression expr, + BVarSymbol varSymbol) { + BLangSimpleVariable simpleVariable = ASTBuilderUtil.createVariable(pos, name, type, expr, varSymbol); + BLangSimpleVariableDef variableDef = ASTBuilderUtil.createVariableDef(pos); + variableDef.var = simpleVariable; + variableDef.setBType(type); + return variableDef; } private List removeDuplicateConstants(BLangPackage pkgNode) { @@ -974,62 +1034,107 @@ private List getConfigurableLangLibInvocationParam(BLangSimpleV typedescExpr)); } - private List desugarGlobalVariables(BLangPackage pkgNode, BLangBlockFunctionBody initFnBody) { + private void desugarTopLevelNodes(BLangPackage pkgNode) { List desugaredGlobalVarList = new ArrayList<>(); + typedescList = new ArrayList<>(); + BLangBlockFunctionBody initFnBody = (BLangBlockFunctionBody) pkgNode.initFunction.body; SymbolEnv initFunctionEnv = SymbolEnv.createFunctionEnv(pkgNode.initFunction, pkgNode.initFunction.symbol.scope, env); + for (int i = 0; i < pkgNode.topLevelNodes.size(); i++) { + TopLevelNode topLevelNode = pkgNode.topLevelNodes.get(i); + switch (topLevelNode.getKind()) { + case TUPLE_VARIABLE, RECORD_VARIABLE, ERROR_VARIABLE -> + desugarVariable((BLangVariable) topLevelNode, initFunctionEnv, initFnBody, + desugaredGlobalVarList); + case VARIABLE -> + desugarGlobalVariables(initFunctionEnv, desugaredGlobalVarList, (BLangVariable) topLevelNode, + initFnBody); + case CONSTANT -> + desugarConstants((BLangConstant) topLevelNode, desugaredGlobalVarList, initFnBody, + initFunctionEnv); + case TYPE_DEFINITION -> { + rewrite((BLangTypeDefinition) topLevelNode, env); + addTypeDescStmtsToInitFunction(initFunctionEnv, desugaredGlobalVarList, initFnBody); + } + } + } + pkgNode.globalVars = desugaredGlobalVarList; + } - for (BLangVariable globalVar : pkgNode.globalVars) { - this.env.enclPkg.topLevelNodes.remove(globalVar); - // This will convert complex variables to simple variables. - switch (globalVar.getKind()) { - case TUPLE_VARIABLE: - BLangNode blockStatementNode = rewrite(globalVar, initFunctionEnv); - List statements = ((BLangBlockStmt) blockStatementNode).stmts; - - int statementSize = statements.size(); - for (BLangStatement bLangStatement : statements) { - addToGlobalVariableList(bLangStatement, initFnBody, globalVar, desugaredGlobalVarList); - } - break; - case RECORD_VARIABLE: - case ERROR_VARIABLE: - blockStatementNode = rewrite(globalVar, initFunctionEnv); - for (BLangStatement statement : ((BLangBlockStmt) blockStatementNode).stmts) { - addToGlobalVariableList(statement, initFnBody, globalVar, desugaredGlobalVarList); - } - break; - default: - long globalVarFlags = globalVar.symbol.flags; - BLangSimpleVariable simpleGlobalVar = (BLangSimpleVariable) globalVar; - if (Symbols.isFlagOn(globalVarFlags, Flags.CONFIGURABLE)) { - if (Symbols.isFlagOn(globalVarFlags, Flags.REQUIRED)) { - // If it is required configuration get directly - List args = getConfigurableLangLibInvocationParam(simpleGlobalVar); - BLangInvocation getValueInvocation = createLangLibInvocationNode("getConfigurableValue", - args, symTable.anydataType, simpleGlobalVar.pos); - simpleGlobalVar.expr = getValueInvocation; - } else { - // If it is optional configuration create if else - simpleGlobalVar.expr = createIfElseFromConfigurable(simpleGlobalVar, initFunctionEnv); - } - } + private void addTypeDescStmtsToInitFunction(SymbolEnv initFunctionEnv, List desugaredGlobalVarList, + BLangBlockFunctionBody initFnBody) { + BSymbol owner = this.env.scope.owner; + for (BLangSimpleVariableDef variableDef : typedescList) { + // typedesc statements are created while rewriting the type node. For that the env will be initFuncEnv. + // But the owner of the symbol should be the package. Hence, correct it here. + BSymbol varSymbol = variableDef.var.symbol; + varSymbol.pkgID = owner.pkgID; + varSymbol.owner = owner; + rewrite(variableDef, initFunctionEnv); + addToInitFunction(variableDef.var, initFnBody); + desugaredGlobalVarList.add(variableDef.var); + } + typedescList.clear(); + } - // Module init should fail if listener is a error value. - if (Symbols.isFlagOn(globalVarFlags, Flags.LISTENER) - && types.containsErrorType(globalVar.expr.getBType())) { - globalVar.expr = ASTBuilderUtil.createCheckExpr(globalVar.expr.pos, globalVar.expr, - globalVar.getBType()); - } + private void desugarVariable(BLangVariable variable, SymbolEnv initFunctionEnv, + BLangBlockFunctionBody initFnBody, List desugaredGlobalVarList) { + BLangNode blockStatementNode = rewrite(variable, initFunctionEnv); + List statements = ((BLangBlockStmt) blockStatementNode).stmts; + addTypeDescStmtsToInitFunction(initFunctionEnv, desugaredGlobalVarList, initFnBody); + for (BLangStatement statement : statements) { + addToGlobalVariableList(statement, initFnBody, variable, desugaredGlobalVarList); + } + } - addToInitFunction(simpleGlobalVar, initFnBody); - desugaredGlobalVarList.add(simpleGlobalVar); - break; - } + private void desugarGlobalVariables(SymbolEnv initFunctionEnv, List desugaredGlobalVarList, + BLangVariable globalVar, BLangBlockFunctionBody initFnBody) { + long globalVarFlags = globalVar.symbol.flags; + BLangSimpleVariable simpleGlobalVar = (BLangSimpleVariable) globalVar; + + // Handle configurable global variables + if (Symbols.isFlagOn(globalVarFlags, Flags.CONFIGURABLE)) { + handleConfigurableGlobalVariable(simpleGlobalVar, initFunctionEnv); + } + + // Handle listener with error type + if (Symbols.isFlagOn(globalVarFlags, Flags.LISTENER) && containsErrorType(globalVar.expr.getBType())) { + handleListenerWithErrorType(globalVar); + } + + BLangType typeNode = simpleGlobalVar.typeNode; + if (typeNode != null && typeNode.getKind() != null) { + rewrite(typeNode, initFunctionEnv); + } + + addTypeDescStmtsToInitFunction(initFunctionEnv, desugaredGlobalVarList, initFnBody); + // Add variable to the initialization function + addToInitFunction(simpleGlobalVar, initFnBody); + desugaredGlobalVarList.add(simpleGlobalVar); + } + + private void handleConfigurableGlobalVariable(BLangSimpleVariable simpleGlobalVar, SymbolEnv initFunctionEnv) { + long globalVarFlags = simpleGlobalVar.symbol.flags; + + if (Symbols.isFlagOn(globalVarFlags, Flags.REQUIRED)) { + // If it is a required configuration, get directly + List args = getConfigurableLangLibInvocationParam(simpleGlobalVar); + simpleGlobalVar.expr = createLangLibInvocationNode("getConfigurableValue", args, + symTable.anydataType, simpleGlobalVar.pos); + } else { + // If it is an optional configuration, create if-else + simpleGlobalVar.expr = createIfElseFromConfigurable(simpleGlobalVar, initFunctionEnv); } + } - this.env.enclPkg.topLevelNodes.addAll(desugaredGlobalVarList); - return desugaredGlobalVarList; + private void handleListenerWithErrorType(BLangVariable globalVar) { + globalVar.expr = ASTBuilderUtil.createCheckExpr(globalVar.expr.pos, globalVar.expr, + globalVar.getBType()); + } + + private boolean containsErrorType(BType type) { + // Check if the type contains an error type + return types.containsErrorType(type); } private void addToGlobalVariableList(BLangStatement bLangStatement, BLangBlockFunctionBody initFnBody, @@ -1069,8 +1174,18 @@ public void visit(BLangImportPackage importPkgNode) { @Override public void visit(BLangTypeDefinition typeDef) { - typeDef.typeNode = rewrite(typeDef.typeNode, env); + BSymbol typeDefSymbol = typeDef.symbol; + if (typeDefSymbol.kind == SymbolKind.TYPE_DEF && typeDefSymbol.origin != VIRTUAL) { + BType referenceType = ((BTypeDefinitionSymbol) typeDefSymbol).referenceType; + int typeTag = Types.getImpliedType(referenceType).tag; + if (typeTag == TypeTags.RECORD || typeTag == TypeTags.MAP || typeTag == TypeTags.TUPLE) { + createTypedescVariable(referenceType, typeDefSymbol.pos); + } + } + if (!Symbols.isFlagOn(typeDef.symbol.flags, Flags.SOURCE_ANNOTATION)) { + typeDef.typeNode = rewrite(typeDef.typeNode, env); + } typeDef.annAttachments.forEach(attachment -> rewrite(attachment, env)); result = typeDef; } @@ -1190,6 +1305,7 @@ private BLangExpression createUserDefinedInitInvocation(Location location, @Override public void visit(BLangRecordTypeNode recordTypeNode) { + createTypedescVariableForAnonType(recordTypeNode); recordTypeNode.fields.addAll(recordTypeNode.includedFields); BRecordTypeSymbol recordTypeSymbol = (BRecordTypeSymbol) recordTypeNode.getBType().tsymbol; @@ -1206,7 +1322,6 @@ public void visit(BLangRecordTypeNode recordTypeNode) { } recordTypeNode.restFieldType = rewrite(recordTypeNode.restFieldType, env); - if (recordTypeNode.isAnonymous && recordTypeNode.isLocal) { BLangUserDefinedType userDefinedType = desugarLocalAnonRecordTypeNode(recordTypeNode); TypeDefBuilderHelper.createTypeDefinitionForTSymbol(recordTypeNode.getBType(), @@ -1215,7 +1330,6 @@ public void visit(BLangRecordTypeNode recordTypeNode) { result = userDefinedType; return; } - result = recordTypeNode; } @@ -1232,6 +1346,9 @@ public void visit(BLangArrayType arrayType) { @Override public void visit(BLangConstrainedType constrainedType) { + if (constrainedType.getBType() != null && constrainedType.getBType().tag == TypeTags.MAP) { + createTypedescVariableForAnonType(constrainedType); + } constrainedType.constraint = rewrite(constrainedType.constraint, env); result = constrainedType; } @@ -1276,8 +1393,12 @@ public void visit(BLangUnionTypeNode unionTypeNode) { @Override public void visit(BLangIntersectionTypeNode intersectionTypeNode) { - List rewrittenConstituents = new ArrayList<>(); + int tag = Types.getImpliedType(intersectionTypeNode.getBType()).tag; + if (tag == TypeTags.RECORD || tag == TypeTags.TUPLE || tag == TypeTags.MAP) { + createTypedescVariableForAnonType(intersectionTypeNode); + } + List rewrittenConstituents = new ArrayList<>(); for (BLangType constituentTypeNode : intersectionTypeNode.constituentTypeNodes) { rewrittenConstituents.add(rewrite(constituentTypeNode, env)); } @@ -1331,6 +1452,7 @@ public void visit(BLangBuiltInRefTypeNode refTypeNode) { @Override public void visit(BLangTupleTypeNode tupleTypeNode) { + createTypedescVariableForAnonType(tupleTypeNode); tupleTypeNode.members.forEach(member -> member.typeNode = rewrite(member.typeNode, env)); tupleTypeNode.restParamType = rewrite(tupleTypeNode.restParamType, env); result = tupleTypeNode; @@ -8860,11 +8982,11 @@ public void visit(BLangJSONArrayLiteral jsonArrayLiteral) { @Override public void visit(BLangConstant constant) { - BConstantSymbol constSymbol = constant.symbol; - BType refType = Types.getImpliedType(constSymbol.literalType); - if (refType.tag <= TypeTags.BOOLEAN || refType.tag == TypeTags.NIL) { - if (refType.tag != TypeTags.NIL && (constSymbol.value == null || + BType impliedType = Types.getImpliedType(constSymbol.literalType); + int tag = impliedType.tag; + if (tag <= TypeTags.BOOLEAN || tag == TypeTags.NIL) { + if (tag != TypeTags.NIL && (constSymbol.value == null || constSymbol.value.value == null)) { throw new IllegalStateException(); } @@ -8874,6 +8996,7 @@ public void visit(BLangConstant constant) { } else { constant.expr = rewriteExpr(constant.expr); } + constant.annAttachments.forEach(attachment -> rewrite(attachment, env)); result = constant; } @@ -9294,9 +9417,18 @@ E rewrite(E statement, SymbolEnv env) { } private List rewriteStmt(List nodeList, SymbolEnv env) { + List prevTypedescList = this.typedescList; for (int i = 0; i < nodeList.size(); i++) { + typedescList = new ArrayList<>(); nodeList.set(i, rewrite(nodeList.get(i), env)); + for (BLangSimpleVariableDef variableDef : typedescList) { + nodeList.add(i, rewrite((E) variableDef, env)); + BSymbol symbol = variableDef.var.symbol; + env.scope.define(symbol.name, symbol); + i++; + } } + this.typedescList = prevTypedescList; return nodeList; } @@ -10752,4 +10884,8 @@ private static void markAndAddPossibleClosureVarsToArrowFunction(BLangArrowFunct simpleVarRef.symbol.closure = true; arrFunction.closureVarSymbols.add(new ClosureVarSymbol(simpleVarRef.symbol, simpleVarRef.pos)); } + + private void clearGlobalVariables() { + this.typedescList = null; + } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ServiceDesugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ServiceDesugar.java index da39e5efca41..4d7b8567d1a2 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ServiceDesugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ServiceDesugar.java @@ -154,8 +154,10 @@ void rewriteServiceVariable(BLangService service, SymbolEnv env, BLangBlockStmt final Location pos = service.pos; - ASTBuilderUtil.defineVariable(service.serviceVariable, env.enclPkg.symbol, names); - env.enclPkg.globalVars.add(service.serviceVariable); + BLangSimpleVariable serviceVariable = service.serviceVariable; + ASTBuilderUtil.defineVariable(serviceVariable, env.enclPkg.symbol, names); + env.enclPkg.globalVars.add(serviceVariable); + env.enclPkg.topLevelNodes.add(serviceVariable); int count = 0; for (BLangExpression attachExpr : service.attachedExprs) { @@ -172,6 +174,7 @@ void rewriteServiceVariable(BLangService service, SymbolEnv env, BLangBlockStmt ASTBuilderUtil.defineVariable(listenerVar, env.enclPkg.symbol, names); listenerVar.symbol.flags |= Flags.LISTENER; env.enclPkg.globalVars.add(listenerVar); + env.enclPkg.topLevelNodes.add(listenerVar); listenerVarRef = ASTBuilderUtil.createVariableRef(pos, listenerVar.symbol); } @@ -186,6 +189,7 @@ void rewriteServiceVariable(BLangService service, SymbolEnv env, BLangBlockStmt null); ASTBuilderUtil.defineVariable(listenerWithoutErrors, env.enclPkg.symbol, names); env.enclPkg.globalVars.add(listenerWithoutErrors); + env.enclPkg.topLevelNodes.add(listenerWithoutErrors); BLangSimpleVarRef checkedRef = ASTBuilderUtil.createVariableRef(pos, listenerWithoutErrors.symbol); listenerVarRef = checkedRef; } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java index 61f0b0af8994..673d2ebdfab1 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java @@ -45,6 +45,7 @@ import org.wso2.ballerinalang.compiler.semantics.model.symbols.SymTag; import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols; import org.wso2.ballerinalang.compiler.semantics.model.types.BArrayType; +import org.wso2.ballerinalang.compiler.semantics.model.types.BErrorType; import org.wso2.ballerinalang.compiler.semantics.model.types.BField; import org.wso2.ballerinalang.compiler.semantics.model.types.BMapType; import org.wso2.ballerinalang.compiler.semantics.model.types.BObjectType; @@ -271,6 +272,7 @@ public class DataflowAnalyzer extends BLangNodeVisitor { private Map uninitializedVars; private Map unusedErrorVarsDeclaredWithVar; private Map unusedLocalVariables; + private final Map symbolOwner; private Map> globalNodeDependsOn; private Map> functionToDependency; private Map> possibleFailureUnInitVars; @@ -293,6 +295,7 @@ private DataflowAnalyzer(CompilerContext context) { this.currDependentSymbolDeque = new ArrayDeque<>(); this.globalVariableRefAnalyzer = GlobalVariableRefAnalyzer.getInstance(context); this.unusedLocalVariables = new HashMap<>(); + this.symbolOwner = new HashMap<>(); } public static DataflowAnalyzer getInstance(CompilerContext context) { @@ -352,7 +355,7 @@ public void visit(BLangPackage pkgNode) { } checkForUninitializedGlobalVars(pkgNode.globalVars); pkgNode.getTestablePkgs().forEach(testablePackage -> visit((BLangPackage) testablePackage)); - this.globalVariableRefAnalyzer.analyzeAndReOrder(pkgNode, this.globalNodeDependsOn); + this.globalVariableRefAnalyzer.analyzeAndReOrder(pkgNode, this.globalNodeDependsOn, this.symbolOwner); this.globalVariableRefAnalyzer.populateFunctionDependencies(this.functionToDependency, pkgNode.globalVars); pkgNode.globalVariableDependencies = globalVariableRefAnalyzer.getGlobalVariablesDependsOn(); checkUnusedImports(pkgNode.imports); @@ -428,6 +431,7 @@ public void visit(BLangFunction funcNode) { funcNode.annAttachments.forEach(bLangAnnotationAttachment -> analyzeNode(bLangAnnotationAttachment.expr, env)); funcNode.requiredParams.forEach(param -> analyzeNode(param, funcEnv)); analyzeNode(funcNode.restParam, funcEnv); + analyzeNode(funcNode.returnTypeNode, env); if (funcNode.flagSet.contains(Flag.OBJECT_CTOR)) { visitFunctionBodyWithDynamicEnv(funcNode, funcEnv); @@ -526,14 +530,15 @@ public void visit(BLangService service) { @Override public void visit(BLangTypeDefinition typeDefinition) { - SymbolEnv typeDefEnv; BSymbol symbol = typeDefinition.symbol; if (typeDefinition.symbol.kind == SymbolKind.TYPE_DEF) { symbol = symbol.type.tsymbol; } - typeDefEnv = SymbolEnv.createTypeEnv(typeDefinition.typeNode, symbol.scope, env); this.currDependentSymbolDeque.push(symbol); - analyzeNode(typeDefinition.typeNode, typeDefEnv); + for (BLangAnnotationAttachment bLangAnnotationAttachment : typeDefinition.annAttachments) { + analyzeNode(bLangAnnotationAttachment.expr, env); + } + analyzeNode(typeDefinition.typeNode, env); this.currDependentSymbolDeque.pop(); } @@ -556,18 +561,19 @@ public void visit(BLangClassDefinition classDef) { this.definiteFailureReached = false; visitedOCE = true; } - SymbolEnv objectEnv = SymbolEnv.createClassEnv(classDef, classDef.symbol.scope, env); this.currDependentSymbolDeque.push(classDef.symbol); for (BLangAnnotationAttachment bLangAnnotationAttachment : classDef.annAttachments) { analyzeNode(bLangAnnotationAttachment.expr, env); } - classDef.fields.forEach(field -> analyzeNode(field, objectEnv)); - classDef.referencedFields.forEach(field -> analyzeNode(field, objectEnv)); + classDef.fields.forEach(field -> analyzeNode(field, this.env)); + classDef.referencedFields.forEach(field -> analyzeNode(field, this.env)); // Visit the constructor with the same scope as the object + analyzeNode(classDef.initFunction, env); if (classDef.initFunction != null) { + SymbolEnv objectEnv = SymbolEnv.createClassEnv(classDef, classDef.symbol.scope, env); if (classDef.initFunction.body == null) { // if the init() function is defined as an outside function definition Optional outerFuncDef = @@ -662,6 +668,11 @@ public void visit(BLangSimpleVariableDef varDefNode) { @Override public void visit(BLangSimpleVariable variable) { BVarSymbol symbol = variable.symbol; + boolean isRecordField = variable.flagSet.contains(Flag.FIELD); + if (!isRecordField) { + this.currDependentSymbolDeque.push(symbol); + } + analyzeNode(variable.typeNode, env); if (symbol == null) { if (variable.expr != null) { @@ -669,8 +680,6 @@ public void visit(BLangSimpleVariable variable) { } return; } - - this.currDependentSymbolDeque.push(symbol); if (variable.typeNode != null && variable.typeNode.getBType() != null) { BType type = variable.typeNode.getBType(); recordGlobalVariableReferenceRelationship(Types.getImpliedType(type).tsymbol); @@ -713,7 +722,9 @@ public void visit(BLangSimpleVariable variable) { if (withInModuleVarLetExpr) { // double pop this.currDependentSymbolDeque.pop(); } - this.currDependentSymbolDeque.pop(); + if (!isRecordField) { + this.currDependentSymbolDeque.pop(); + } } } @@ -1588,6 +1599,10 @@ private List getFieldNames(BLangTableConstructorExpr constructorExpr) { @Override public void visit(BLangRecordLiteral recordLiteral) { + BType type = recordLiteral.getBType(); + if (type != null) { + recordGlobalVariableReferenceRelationship(Types.getImpliedType(type).tsymbol); + } for (RecordLiteralNode.RecordField field : recordLiteral.fields) { if (field.isKeyValueField()) { BLangRecordLiteral.BLangRecordKeyValueField keyValuePair = @@ -1728,6 +1743,8 @@ public void visit(BLangErrorConstructorExpr errorConstructorExpr) { for (BLangNamedArgsExpression namedArg : errorConstructorExpr.namedArgs) { analyzeNode(namedArg, env); } + BType detailType = ((BErrorType) Types.getImpliedType(errorConstructorExpr.getBType())).detailType; + recordGlobalVariableReferenceRelationship(detailType.tsymbol); } @Override @@ -2114,6 +2131,7 @@ public void visit(BLangLambdaFunction bLangLambdaFunction) { BLangFunction funcNode = bLangLambdaFunction.function; SymbolEnv funcEnv = SymbolEnv.createFunctionEnv(funcNode, funcNode.symbol.scope, env); visitFunctionBodyWithDynamicEnv(funcNode, funcEnv); + recordGlobalVariableReferenceRelationship(funcNode.symbol); } @Override @@ -2251,7 +2269,7 @@ public void visit(BLangUserDefinedType userDefinedType) { if (this.currDependentSymbolDeque.isEmpty()) { return; } - BType resolvedType = Types.getImpliedType(userDefinedType.getBType()); + BType resolvedType = userDefinedType.getBType(); if (resolvedType == symTable.semanticError) { return; } @@ -2417,6 +2435,10 @@ public void visit(BLangInferredTypedescDefaultNode inferTypedescExpr) { @Override public void visit(BLangErrorType errorType) { + BLangType detailType = errorType.detailType; + if (detailType != null && detailType.getBType() != null) { + recordGlobalVariableReferenceRelationship(Types.getImpliedType(detailType.getBType()).tsymbol); + } } @Override @@ -2458,6 +2480,9 @@ public void visit(BLangTupleVariable bLangTupleVariable) { analyzeNode(bLangTupleVariable.typeNode, env); populateUnusedVariableMapForNonSimpleBindingPatternVariables(this.unusedLocalVariables, bLangTupleVariable); this.currDependentSymbolDeque.push(bLangTupleVariable.symbol); + for (BLangVariable memberVariable : bLangTupleVariable.memberVariables) { + symbolOwner.put(memberVariable.symbol, bLangTupleVariable.symbol); + } analyzeNode(bLangTupleVariable.expr, env); this.currDependentSymbolDeque.pop(); } @@ -2472,6 +2497,10 @@ public void visit(BLangRecordVariable bLangRecordVariable) { analyzeNode(bLangRecordVariable.typeNode, env); populateUnusedVariableMapForNonSimpleBindingPatternVariables(this.unusedLocalVariables, bLangRecordVariable); this.currDependentSymbolDeque.push(bLangRecordVariable.symbol); + for (BLangRecordVariable.BLangRecordVariableKeyValue recordVariableKeyValue : + bLangRecordVariable.variableList) { + symbolOwner.put(recordVariableKeyValue.valueBindingPattern.symbol, bLangRecordVariable.symbol); + } analyzeNode(bLangRecordVariable.expr, env); this.currDependentSymbolDeque.pop(); } @@ -2486,6 +2515,21 @@ public void visit(BLangErrorVariable bLangErrorVariable) { analyzeNode(bLangErrorVariable.typeNode, env); populateUnusedVariableMapForNonSimpleBindingPatternVariables(this.unusedLocalVariables, bLangErrorVariable); this.currDependentSymbolDeque.push(bLangErrorVariable.symbol); + BSymbol symbol = bLangErrorVariable.symbol; + if (bLangErrorVariable.message != null) { + symbolOwner.put(bLangErrorVariable.message.symbol, symbol); + } + if (bLangErrorVariable.cause != null) { + symbolOwner.put(bLangErrorVariable.cause.symbol, symbol); + } + if (bLangErrorVariable.restDetail != null) { + symbolOwner.put(bLangErrorVariable.restDetail.symbol, symbol); + } + + for (BLangErrorVariable.BLangErrorDetailEntry errorDetailEntry : bLangErrorVariable.detail) { + symbolOwner.put(errorDetailEntry.valueBindingPattern.symbol, bLangErrorVariable.symbol); + } + analyzeNode(bLangErrorVariable.expr, env); this.currDependentSymbolDeque.pop(); } @@ -2616,23 +2660,24 @@ private void recordGlobalVariableReferenceRelationship(BSymbol symbol) { boolean globalVarSymbol = isGlobalVarSymbol(symbol); BSymbol ownerSymbol = this.env.scope.owner; - boolean isInPkgLevel = ownerSymbol.getKind() == SymbolKind.PACKAGE; - // Restrict to observations made in pkg level. - if (isInPkgLevel && (globalVarSymbol || symbol instanceof BTypeSymbol) - || (ownerSymbol.tag == SymTag.LET && globalVarSymbol)) { - BSymbol dependent = this.currDependentSymbolDeque.peek(); - addDependency(dependent, symbol); - } else if (ownerSymbol.kind == SymbolKind.FUNCTION && globalVarSymbol) { - // Global variable ref from non package level. - BInvokableSymbol invokableOwnerSymbol = (BInvokableSymbol) ownerSymbol; - addDependency(invokableOwnerSymbol, symbol); - } else if (ownerSymbol.kind == SymbolKind.OBJECT && globalVarSymbol) { - // Global variable reference from a field assignment of an object or a service. - // Or global variable reference from a init function of an object or a service. - addDependency(ownerSymbol, symbol); - } else if (ownerSymbol.kind == SymbolKind.RECORD && globalVarSymbol) { - // Global variable reference from a field assignment of an record type declaration. - addDependency(ownerSymbol, symbol); + switch (ownerSymbol.getKind()) { + case FUNCTION : + // Global variable ref from non package level. + case OBJECT: + // Global variable reference from a field assignment of an object or a service. + // Or global variable reference from an init function of an object or a service. + case RECORD: + // Global variable reference from a field assignment of a record type declaration. + if (globalVarSymbol) { + addDependency(ownerSymbol, symbol); + break; + } + // fall through + default: + if (globalVarSymbol || symbol instanceof BTypeSymbol || ownerSymbol.tag == SymTag.LET) { + BSymbol dependent = this.currDependentSymbolDeque.peek(); + addDependency(dependent, symbol); + } } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java index de443d69b5be..3db1a3270edc 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java @@ -2845,6 +2845,10 @@ boolean hasSameReadonlyFlag(BType source, BType target) { @Override public Boolean visit(BTupleType t, BType s) { + if (t == s) { + return true; + } + List tTupleTypes = t.getTupleTypes(); if (((!tTupleTypes.isEmpty() && checkAllTupleMembersBelongNoType(tTupleTypes)) || (t.restType != null && t.restType.tag == TypeTags.NONE)) && diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/cyclefind/GlobalVariableRefAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/cyclefind/GlobalVariableRefAnalyzer.java index e91e441a25ae..443891f9fb2f 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/cyclefind/GlobalVariableRefAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/cyclefind/GlobalVariableRefAnalyzer.java @@ -46,8 +46,8 @@ import java.util.Deque; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -64,6 +64,7 @@ public class GlobalVariableRefAnalyzer { private final BLangDiagnosticLog dlog; private BLangPackage pkgNode; private Map> globalNodeDependsOn; + Map symbolOwner; private Map> globalVariablesDependsOn; private final Map dependencyNodes; private final Deque nodeInfoStack; @@ -228,54 +229,21 @@ private boolean isGlobalVarSymbol(BSymbol symbol, Set globalVars) { } /** - * Analyze the global variable references and reorder them or emit error if they contain cyclic references. + * Analyze the global references and reorder them or emit error if they contain cyclic references. * * @param pkgNode package to be analyzed. * @param globalNodeDependsOn symbol dependency relationship. + * @param symbolOwner symbol owner relationship. */ - public void analyzeAndReOrder(BLangPackage pkgNode, Map> globalNodeDependsOn) { + public void analyzeAndReOrder(BLangPackage pkgNode, Map> globalNodeDependsOn, + Map symbolOwner) { this.dlog.setCurrentPackageId(pkgNode.packageID); this.pkgNode = pkgNode; this.globalNodeDependsOn = globalNodeDependsOn; + this.symbolOwner = symbolOwner; resetAnalyzer(); - List globalVarsAndDependentFuncs = getGlobalVariablesAndDependentFunctions(); - - pruneDependencyRelations(); - - Set sorted = new LinkedHashSet<>(); - LinkedList dependencies = new LinkedList<>(); - - for (BSymbol symbol : globalVarsAndDependentFuncs) { - List dependencyTrain = analyzeDependenciesStartingFrom(symbol); - dependencies.addAll(dependencyTrain); - - Set symbolsProviders = globalNodeDependsOn.get(symbol); - boolean symbolHasProviders = symbolsProviders != null && !symbolsProviders.isEmpty(); - boolean notInSortedList = !sorted.contains(symbol); - - // Independent variable declaration, add to sorted list. - if (notInSortedList && !symbolHasProviders) { - moveAndAppendToSortedList(symbol, dependencies, sorted); - } - // Dependent variable, and all the dependencies are satisfied, add to sorted list. - if (notInSortedList && symbolHasProviders && sorted.containsAll(symbolsProviders)) { - moveAndAppendToSortedList(symbol, dependencies, sorted); - } - - // If we can satisfy the dependencies' dependencies then we can add those dependencies to sorted list now. - addDependenciesDependencies(dependencies, sorted); - } - sorted.addAll(dependencies); - - // Cyclic error found no need to sort. - if (cyclicErrorFound) { - return; - } - - sortConstants(sorted); - projectSortToGlobalVarsList(sorted); - projectSortToTopLevelNodesList(); + reOrderTopLevelNodeList(); } private List analyzeDependenciesStartingFrom(BSymbol symbol) { @@ -298,148 +266,51 @@ private List analyzeDependenciesStartingFrom(BSymbol symbol) { return new ArrayList<>(); } - private void pruneDependencyRelations() { - List dependents = new ArrayList<>(this.globalNodeDependsOn.keySet()); - Set visited = new HashSet<>(); - for (BSymbol dependent : dependents) { - // Taking a copy as we need to modify the original list. - List providers = new ArrayList<>(this.globalNodeDependsOn.get(dependent)); - for (BSymbol provider : providers) { - pruneFunctions(dependent, provider, this.globalNodeDependsOn, visited); - } - } - } + private void reOrderTopLevelNodeList() { + Map varMap = collectAssociateSymbolsWithTopLevelNodes(); - private void pruneFunctions(BSymbol dependent, BSymbol provider, Map> globalNodeDependsOn, - Set visited) { - if (visited.contains(provider)) { - return; - } else { - visited.add(provider); - } - - // Dependent has a dependency on a global var. - if (provider.tag != SymTag.FUNCTION) { - return; + Set sorted = new LinkedHashSet<>(); + for (BSymbol symbol : varMap.keySet()) { + sorted.addAll(analyzeDependenciesStartingFrom(symbol)); } - // Provider is a function. - // And doesn't have dependency on a global variable. We can prune provider. - if (!globalNodeDependsOn.containsKey(provider) || globalNodeDependsOn.get(provider).isEmpty()) { - globalNodeDependsOn.get(dependent).remove(provider); + // Cyclic error found no need to sort. + if (cyclicErrorFound) { return; } - // Taking a copy as we need to modify the original list. - List providersProviders = new ArrayList<>(globalNodeDependsOn.get(provider)); - for (BSymbol prov : providersProviders) { - pruneFunctions(provider, prov, globalNodeDependsOn, visited); - } - } - - private void addDependenciesDependencies(LinkedList dependencies, Set sorted) { - // For each dependency if they satisfy their dependencies in sorted list, then add them to sorted list. - ArrayList depCopy = new ArrayList<>(dependencies); - for (BSymbol dep : depCopy) { - Set depsDependencies = globalNodeDependsOn.getOrDefault(dep, new LinkedHashSet<>()); - if (!depsDependencies.isEmpty() && sorted.containsAll(depsDependencies)) { - moveAndAppendToSortedList(dep, dependencies, sorted); + Set sortedTopLevelNodes = new LinkedHashSet<>(); + for (BSymbol symbol : sorted) { + if (varMap.containsKey(symbol)) { + sortedTopLevelNodes.add(varMap.get(symbol)); } } - } - - private void projectSortToTopLevelNodesList() { - // Swap global variable nodes in 'topLevelNodes' list to reflect sorted global variables. - List topLevelPositions = new ArrayList<>(); - for (BLangVariable globalVar : pkgNode.globalVars) { - topLevelPositions.add(pkgNode.topLevelNodes.indexOf(globalVar)); - } - topLevelPositions.sort(Comparator.comparingInt(i -> i)); - for (int i = 0; i < topLevelPositions.size(); i++) { - Integer targetIndex = topLevelPositions.get(i); - pkgNode.topLevelNodes.set(targetIndex, pkgNode.globalVars.get(i)); - } - topLevelPositions = new ArrayList<>(); - for (BLangConstant constant : pkgNode.constants) { - topLevelPositions.add(pkgNode.topLevelNodes.indexOf(constant)); - } - topLevelPositions.sort(Comparator.comparingInt(i -> i)); - for (int i = 0; i < topLevelPositions.size(); i++) { - Integer targetIndex = topLevelPositions.get(i); - pkgNode.topLevelNodes.set(targetIndex, pkgNode.constants.get(i)); - } + sortedTopLevelNodes.addAll(pkgNode.topLevelNodes); + this.pkgNode.topLevelNodes.clear(); + this.pkgNode.topLevelNodes.addAll(sortedTopLevelNodes); } - private void projectSortToGlobalVarsList(Set sorted) { - Map varMap = new HashMap<>(); - this.pkgNode.globalVars.forEach(globalVar -> { - if (globalVar.symbol != null) { - varMap.put(globalVar.symbol, globalVar); - } - }); - - List sortedGlobalVars = sorted.stream() - .filter(varMap::containsKey) - .map(varMap::get) - .toList(); - - if (sortedGlobalVars.size() != this.pkgNode.globalVars.size()) { - List symbolLessGlobalVars = this.pkgNode.globalVars.stream() - .filter(g -> g.symbol == null) - .toList(); - sortedGlobalVars.addAll(symbolLessGlobalVars); - } - this.pkgNode.globalVars.clear(); - this.pkgNode.globalVars.addAll(sortedGlobalVars); - } - - private void sortConstants(Set sorted) { - Map varMap = this.pkgNode.constants.stream() - .collect(Collectors.toMap(k -> k.symbol, k -> k)); - - List sortedConstants = sorted.stream() - .filter(varMap::containsKey) - .map(varMap::get) - .toList(); - - if (sortedConstants.size() != this.pkgNode.constants.size()) { - List symbolLessGlobalVars = this.pkgNode.constants.stream() - .filter(c -> !sortedConstants.contains(c)) - .toList(); - sortedConstants.addAll(symbolLessGlobalVars); - } - this.pkgNode.constants.clear(); - this.pkgNode.constants.addAll(sortedConstants); - } - - private List getGlobalVariablesAndDependentFunctions() { - List dependents = new ArrayList<>(); - - for (BSymbol s : globalNodeDependsOn.keySet()) { - if ((s.tag & SymTag.FUNCTION) == SymTag.FUNCTION) { - dependents.add(s); - } - } - - for (BLangVariable var : this.pkgNode.globalVars) { - if (var.symbol != null) { - dependents.add(var.symbol); - } - } + private Map collectAssociateSymbolsWithTopLevelNodes() { + Map varMap = new LinkedHashMap<>(); - for (BLangConstant constant : this.pkgNode.constants) { - if (constant.symbol != null) { - dependents.add(constant.symbol); + for (TopLevelNode topLevelNode : this.pkgNode.topLevelNodes) { + BSymbol symbol = getSymbolFromTopLevelNode(topLevelNode); + if (symbol != null) { + varMap.put(symbol, topLevelNode); } } - return dependents; + return varMap; } - private void moveAndAppendToSortedList(BSymbol symbol, List moveFrom, Set sorted) { - sorted.add(symbol); - moveFrom.remove(symbol); + private BSymbol getSymbolFromTopLevelNode(TopLevelNode topLevelNode) { + return switch (topLevelNode.getKind()) { + case VARIABLE, RECORD_VARIABLE, TUPLE_VARIABLE, ERROR_VARIABLE -> ((BLangVariable) topLevelNode).symbol; + case TYPE_DEFINITION -> ((BLangTypeDefinition) topLevelNode).symbol.type.tsymbol; + case CONSTANT -> ((BLangConstant) topLevelNode).symbol; + default -> null; + }; } private int analyzeProvidersRecursively(NodeInfo node) { @@ -454,8 +325,9 @@ private int analyzeProvidersRecursively(NodeInfo node) { Set providers = globalNodeDependsOn.getOrDefault(node.symbol, new LinkedHashSet<>()); for (BSymbol providerSym : providers) { + BSymbol symbol = symbolOwner.getOrDefault(providerSym, providerSym); NodeInfo providerNode = - dependencyNodes.computeIfAbsent(providerSym, s -> new NodeInfo(curNodeId++, providerSym)); + dependencyNodes.computeIfAbsent(providerSym, s -> new NodeInfo(curNodeId++, symbol)); int lastLowLink = analyzeProvidersRecursively(providerNode); if (providerNode.onStack) { node.lowLink = Math.min(node.lowLink, lastLowLink); diff --git a/docs/bir-spec/src/main/resources/kaitai/bir.ksy b/docs/bir-spec/src/main/resources/kaitai/bir.ksy index c4ac5bb12572..0184d94d832f 100644 --- a/docs/bir-spec/src/main/resources/kaitai/bir.ksy +++ b/docs/bir-spec/src/main/resources/kaitai/bir.ksy @@ -1444,6 +1444,11 @@ types: - id: typedesc_operand type: operand if: has_typedesc_operand == 1 + - id: has_element_typedesc_operand + type: s1 + - id: element_typedesc_operand + type: operand + if: has_element_typedesc_operand == 1 - id: size_operand type: operand - id: init_values_count diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/JsonValues.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/JsonValues.java index c79f1193afb0..ca50c27f8a92 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/JsonValues.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/JsonValues.java @@ -22,6 +22,7 @@ import io.ballerina.runtime.api.types.Type; import io.ballerina.runtime.api.utils.JsonUtils; import io.ballerina.runtime.api.utils.StringUtils; +import io.ballerina.runtime.api.utils.TypeUtils; import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BString; @@ -47,7 +48,7 @@ private JsonValues() { } public static BMap testConvertJSONToRecord(Object record, BTypedesc t) throws BError { - Type describingType = t.getDescribingType(); + Type describingType = TypeUtils.getImpliedType(t.getDescribingType()); if (describingType instanceof StructureType) { return convertJSONToRecord(record, (StructureType) describingType); } else { diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/Values.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/Values.java index 02f1ce709066..5c11d88d15bc 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/Values.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/runtime/api/tests/Values.java @@ -341,7 +341,7 @@ public static Object validate(Object value, BTypedesc typedesc) { } public static Object validateRecord(Object value, BTypedesc typedesc) { - Type describingType = typedesc.getDescribingType(); + Type describingType = TypeUtils.getImpliedType(typedesc.getDescribingType()); Long age = ((BMap) value).getIntValue(StringUtils.fromString("age")); for (Field field : ((BRecordType) describingType).getFields().values()) { BMap annotations = ((AnnotatableType) field.getFieldType()).getAnnotations(); diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/tests/VariableReturnType.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/tests/VariableReturnType.java index 891e1beb46a4..cd509a065b5e 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/tests/VariableReturnType.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/nativeimpl/jvm/tests/VariableReturnType.java @@ -155,7 +155,7 @@ public static MapValue query(BString query, BTypedesc typedesc) } public static BStream getStreamOfRecords(ObjectValue objectValue, BStream strm, BTypedesc typedesc) { - RecordType streamConstraint = (RecordType) typedesc.getDescribingType(); + RecordType streamConstraint = (RecordType) TypeUtils.getImpliedType(typedesc.getDescribingType()); Assert.assertSame(streamConstraint, TypeUtils.getImpliedType(strm.getConstraintType())); return strm; } @@ -163,7 +163,7 @@ public static BStream getStreamOfRecords(ObjectValue objectValue, BStream strm, public static ArrayValue getTuple(BTypedesc td1, BTypedesc td2, BTypedesc td3) { List memTypes = new ArrayList<>(); memTypes.add(td1.getDescribingType()); - memTypes.add(td2.getDescribingType()); + memTypes.add(TypeUtils.getImpliedType(td2.getDescribingType())); memTypes.add(td3.getDescribingType()); BTupleType tupleType = new BTupleType(memTypes); @@ -195,7 +195,7 @@ public static ArrayValue getTupleWithRestDesc(BTypedesc td1, BTypedesc td2, BTyp } public static MapValue getRecord(BTypedesc td) { - BRecordType recType = (BRecordType) td.getDescribingType(); + BRecordType recType = (BRecordType) TypeUtils.getImpliedType(td.getDescribingType()); MapValueImpl person = new MapValueImpl<>(recType); if (recType.getName().equals("Person")) { @@ -262,6 +262,7 @@ public static Object getInvalidValue(BTypedesc td1, BTypedesc td2) { } private static Object getValue(Type type) { + type = TypeUtils.getImpliedType(type); switch (type.getTag()) { case INT_TAG: return 150L; diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DisplayAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DisplayAnnotationTest.java index 43c6ae0f08b3..13ec22f3419c 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DisplayAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DisplayAnnotationTest.java @@ -97,7 +97,7 @@ public void testDisplayAnnotOnObjectAndMemberFunction() { @Test public void testDisplayAnnotOnRecord() { - TypeDefinition typeDefinition = result.getAST().getTypeDefinitions().get(15); + TypeDefinition typeDefinition = result.getAST().getTypeDefinitions().get(3); List annot = typeDefinition.getAnnotationAttachments(); Assert.assertEquals(annot.size(), 1); Assert.assertEquals(annot.get(0).getExpression().toString(), diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java index aa729a01e4b6..21671cfbea5e 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java @@ -131,6 +131,8 @@ public void moduleVariableWithLetExprCausingCycle() { BAssertUtil.validateError(cycle, i++, "illegal cyclic reference '[modVarQueryLet1, queryRef, modVarQuery]'", 19, 1); BAssertUtil.validateError(cycle, i++, "illegal cyclic reference '[modVarQueryLet2, queryRef2]'", 20, 1); + BAssertUtil.validateError(cycle, i++, + "illegal cyclic reference '[recD, RecordTypeWithDefaultLetExpr, moduleCode]'", 26, 1); Assert.assertEquals(cycle.getDiagnostics().length, i); } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failLockWithinLock b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failLockWithinLock index 776a8a92d311..0cfa00d4b41c 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failLockWithinLock +++ b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failLockWithinLock @@ -8,8 +8,8 @@ failLockWithinLock function() -> (int, string) { %14(LOCAL) error; %16(TEMP) string; %18(TEMP) (); - %19(TEMP) typeDesc; - %20(TEMP) map; + %19(TEMP) map; + %20(TEMP) typeDesc; %21(TEMP) string; %22(TEMP) string; %23(TEMP) map; @@ -50,11 +50,11 @@ failLockWithinLock function() -> (int, string) { %16 = ConstLoad custom error; %18 = ConstLoad 0; %12 = %18; - %19 = newType map; + %20 = newType map; %21 = ConstLoad message; %22 = ConstLoad error value; - %20 = NewMap %19{%21:%22}; - %23 = cloneReadOnly(%20) -> bb8; + %19 = NewMap %20{%21:%22}; + %23 = cloneReadOnly(%19) -> bb8; } bb8 { %14 = error error(%16, %12, %23); @@ -101,10 +101,10 @@ failLockWithinLock function() -> (int, string) { panic %12; } bb19 { - %19 = newType (int, string); + %20 = newType (int, string); %41 = ConstLoad 2; %42 = lockWithinLockInt; - %0 = newArray %19[%41]{%42,lockWithinLockString}; + %0 = newArray %20[%41]{%42,lockWithinLockString}; GOTO bb20; } bb20 { diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failWithinOnFail b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failWithinOnFail index 7703bcf0ce93..378fae3b3de0 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failWithinOnFail +++ b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/failWithinOnFail @@ -8,8 +8,8 @@ failWithinOnFail function() -> string|error { %14(LOCAL) error; %17(TEMP) error; %18(TEMP) (); - %19(TEMP) typeDesc; - %20(TEMP) map; + %19(TEMP) map; + %20(TEMP) typeDesc; %21(TEMP) string; %22(TEMP) string; %23(TEMP) map; @@ -32,11 +32,11 @@ failWithinOnFail function() -> string|error { %9 = ConstLoad custom error; %18 = ConstLoad 0; %17 = %18; - %19 = newType map; + %20 = newType map; %21 = ConstLoad message; %22 = ConstLoad error value; - %20 = NewMap %19{%21:%22}; - %23 = cloneReadOnly(%20) -> bb3; + %19 = NewMap %20{%21:%22}; + %23 = cloneReadOnly(%19) -> bb3; } bb3 { %14 = error error(%9, %17, %23); diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/globalVarsAndAnonFunctions b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/globalVarsAndAnonFunctions index 46c78071843e..eb207acbaa25 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/globalVarsAndAnonFunctions +++ b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/globalVarsAndAnonFunctions @@ -1,15 +1,15 @@ public globalVarsAndAnonFunctions function() -> () { %0(RETURN) (); %1(SYNTHETIC) map; - %2(TEMP) typeDesc; + %3(TEMP) typeDesc; %4(TEMP) any|error; %5(TEMP) int; %7(TEMP) string; %12(LOCAL) function(int) -> int; bb0 { - %2 = newType map; - %1 = NewMap %2{}; + %3 = newType map; + %1 = NewMap %3{}; %5 = ConstLoad 3; %4 = %5; %7 = ConstLoad a; diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/mapInits b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/mapInits index c63308da760c..2708c861c1bc 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/mapInits +++ b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/mapInits @@ -1,8 +1,8 @@ mapInits function() -> (string|(), int|()) { %0(RETURN) (string|(), int|()); - %1(LOCAL) map; - %2(TEMP) typeDesc; - %4(LOCAL) Person; + %1(SYNTHETIC) typeDesc>; + %3(LOCAL) map; + %5(LOCAL) Person; %7(TEMP) string; %8(TEMP) string; %9(TEMP) string; @@ -10,6 +10,7 @@ mapInits function() -> (string|(), int|()) { %11(TEMP) string; %12(TEMP) string; %13(TEMP) Employee; + %18(TEMP) typeDesc; %20(SYNTHETIC) string|(); %21(SYNTHETIC) Employee|(); %25(SYNTHETIC) Employee|(); @@ -37,23 +38,22 @@ mapInits function() -> (string|(), int|()) { %114(SYNTHETIC) boolean; bb0 { - %2 = newType map; - %1 = NewMap %2{}; - %2 = newType Person; + %1 = newType map; + %3 = NewMap %1{}; %7 = ConstLoad name; %8 = ConstLoad Jack; %9 = ConstLoad age; %10 = ConstLoad 25; %11 = ConstLoad address; %12 = ConstLoad Usa; - %4 = NewMap %2{%7:%8,%9:%10,%11:%12}; - %13 = %4; + %5 = NewMap $typedesc$Person{%7:%8,%9:%10,%11:%12}; + %13 = %5; %7 = ConstLoad jack; - %1[%7] = %13; - %2 = newType (string|(), int|()); + %3[%7] = %13; + %18 = newType (string|(), int|()); %10 = ConstLoad 2; %8 = ConstLoad jack; - %21 = %1[%8]; + %21 = %3[%8]; %25 = %21; %30 = ConstLoad true; %30? bb1 : bb2; @@ -152,7 +152,7 @@ mapInits function() -> (string|(), int|()) { } bb24 { %12 = ConstLoad jack; - %74 = %1[%12]; + %74 = %3[%12]; %78 = %74; %30 = ConstLoad true; %30? bb25 : bb26; @@ -250,7 +250,7 @@ mapInits function() -> (string|(), int|()) { GOTO bb48; } bb48 { - %0 = newArray %2[%10]{%20,%73}; + %0 = newArray %18[%10]{%20,%73}; GOTO bb49; } bb49 { diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setNillableField b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setNillableField index d216c36953cb..723f77f33d8e 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setNillableField +++ b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setNillableField @@ -1,26 +1,24 @@ setNillableField function() -> () { %0(RETURN) (); %1(LOCAL) R2; - %2(TEMP) typeDesc; - %4(TEMP) string; - %5(TEMP) int|(); - %6(TEMP) int; - %12(TEMP) (); + %3(TEMP) string; + %4(TEMP) int|(); + %5(TEMP) int; + %11(TEMP) (); bb0 { - %2 = newType R2; - %4 = ConstLoad x; - %6 = ConstLoad 1; - %5 = %6; - %1 = NewMap %2{%4:%5}; - %6 = ConstLoad 2; - %5 = %6; - %4 = ConstLoad x; - %1[%4] = %5; - %12 = ConstLoad 0; - %5 = %12; - %4 = ConstLoad x; - %1[%4] = %5; + %3 = ConstLoad x; + %5 = ConstLoad 1; + %4 = %5; + %1 = NewMap $typedesc$R2{%3:%4}; + %5 = ConstLoad 2; + %4 = %5; + %3 = ConstLoad x; + %1[%3] = %4; + %11 = ConstLoad 0; + %4 = %11; + %3 = ConstLoad x; + %1[%3] = %4; %0 = ConstLoad 0; GOTO bb1; } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setOptionalField b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setOptionalField index b792e069ca63..8e0f02260b01 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setOptionalField +++ b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setOptionalField @@ -1,22 +1,20 @@ setOptionalField function() -> () { %0(RETURN) (); %1(LOCAL) R3; - %2(TEMP) typeDesc; - %4(TEMP) int; - %6(TEMP) string; - %7(TEMP) int|(); - %8(TEMP) (); + %3(TEMP) int; + %5(TEMP) string; + %6(TEMP) int|(); + %7(TEMP) (); bb0 { - %2 = newType R3; - %1 = NewMap %2{}; - %4 = ConstLoad 2; - %6 = ConstLoad x; - %1[%6] = %4; - %8 = ConstLoad 0; - %7 = %8; - %6 = ConstLoad x; - %1[%6] = %7; + %1 = NewMap $typedesc$R3{}; + %3 = ConstLoad 2; + %5 = ConstLoad x; + %1[%5] = %3; + %7 = ConstLoad 0; + %6 = %7; + %5 = ConstLoad x; + %1[%5] = %6; %0 = ConstLoad 0; GOTO bb1; } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setRequiredField b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setRequiredField index 24101ec4fd7a..dede62304784 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setRequiredField +++ b/tests/jballerina-unit-test/src/test/resources/test-src/bir/bir-dump/setRequiredField @@ -1,18 +1,16 @@ setRequiredField function() -> () { %0(RETURN) (); %1(LOCAL) R1; - %2(TEMP) typeDesc}>; - %4(TEMP) string; - %5(TEMP) int; + %3(TEMP) string; + %4(TEMP) int; bb0 { - %2 = newType R1; - %4 = ConstLoad x; - %5 = ConstLoad 1; - %1 = NewMap %2{%4:%5}; - %5 = ConstLoad 2; - %4 = ConstLoad x; - %1[%4] = %5; + %3 = ConstLoad x; + %4 = ConstLoad 1; + %1 = NewMap $typedesc$R1{%3:%4}; + %4 = ConstLoad 2; + %3 = ConstLoad x; + %1[%3] = %4; %0 = ConstLoad 0; GOTO bb1; } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/tuple-type-definitions-cyclic.bal b/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/tuple-type-definitions-cyclic.bal index 8d3ef4fcf0fc..e530f2e7645a 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/tuple-type-definitions-cyclic.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/tuple-type-definitions-cyclic.bal @@ -278,7 +278,7 @@ function testCastingToImmutableCyclicTuple() { error err = b; assert(err.message(), "{ballerina}TypeCastError"); assert( checkpanic err.detail()["message"], "incompatible types: 'MyCyclicTuple' cannot be " + - "cast to '[int,(MyCyclicTuple[] & readonly)] & readonly'"); + "cast to '(MyCyclicTuple & readonly)'"); MyCyclicTuple c = <[int, MyCyclicTuple[]] & readonly> [1, []]; MyCyclicTuple & readonly d = c; assert(d is [int, MyCyclicTuple[]] & readonly, true);