Skip to content

Commit

Permalink
Merge pull request #41017 from Nadeeshan96/master-fix-large-arr-36440
Browse files Browse the repository at this point in the history
Support large list and mapping constructors
  • Loading branch information
warunalakshitha authored Aug 16, 2023
2 parents d13b79d + bfad17e commit a9e9d76
Show file tree
Hide file tree
Showing 38 changed files with 9,288 additions and 213 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved.
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package io.ballerina.runtime.internal.util;

import io.ballerina.runtime.api.values.BArray;
import io.ballerina.runtime.api.values.BMap;
import io.ballerina.runtime.api.values.BMapInitialValueEntry;
import io.ballerina.runtime.internal.values.HandleValue;
import io.ballerina.runtime.internal.values.ListInitialValueEntry;
import io.ballerina.runtime.internal.values.MappingInitialValueEntry;

/**
* Util methods required for handling large arrays, tuples, maps and records.
*
* @since 2201.8.0
*/
public class LargeStructureUtils {

private LargeStructureUtils() {}

public static HandleValue getListInitialValueEntryArray(long size) {
return new HandleValue(new ListInitialValueEntry[(int) size]);
}

public static void setExpressionEntry(HandleValue arrayList, Object element, long index) {
ListInitialValueEntry[] arr = (ListInitialValueEntry[]) arrayList.getValue();
arr[(int) index] = new ListInitialValueEntry.ExpressionEntry(element);
}

public static void setSpreadEntry(HandleValue arrayList, Object element, long index) {
ListInitialValueEntry[] arr = (ListInitialValueEntry[]) arrayList.getValue();
arr[(int) index] = new ListInitialValueEntry.SpreadEntry((BArray) element);
}

public static HandleValue getBMapInitialValueEntryArray(long size) {
return new HandleValue(new BMapInitialValueEntry[(int) size]);
}

public static void setKeyValueEntry(HandleValue arrayList, Object key, Object value, long index) {
BMapInitialValueEntry[] arr = (BMapInitialValueEntry[]) arrayList.getValue();
arr[(int) index] = new MappingInitialValueEntry.KeyValueEntry(key, value);
}

public static void setSpreadFieldEntry(HandleValue arrayList, Object spreadFieldEntry, long index) {
BMapInitialValueEntry[] arr = (BMapInitialValueEntry[]) arrayList.getValue();
arr[(int) index] = new MappingInitialValueEntry.SpreadFieldEntry((BMap) spreadFieldEntry);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ public class HandleValue implements BHandle, RefValue {
private Object value;
private BTypedesc typedesc;

@Deprecated
public HandleValue(Object value) {
this.value = value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,15 @@ public static void rearrangeBasicBlocks(BIRNode.BIRFunction birFunction) {
int currentBBId = 0;
// Re-arrange basic blocks
for (BIRNode.BIRBasicBlock bb : birFunction.basicBlocks) {
bb.number = currentBBId;
bb.id = new Name(BIRBasicBlock.BIR_BASIC_BLOCK_PREFIX + currentBBId++);
currentBBId = renumberBasicBlock(currentBBId, bb);
}
// Re-arrange error entries
birFunction.errorTable.sort(Comparator.comparingInt(o -> o.trapBB.number));
}

public static int renumberBasicBlock(int newBBNum, BIRBasicBlock bb) {
bb.number = newBBNum;
bb.id = new Name(BIRBasicBlock.BIR_BASIC_BLOCK_PREFIX + newBBNum);
return newBBNum + 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ public class JvmConstants {
public static final String ERROR_UTILS = "io/ballerina/runtime/internal/ErrorUtils";
public static final String ERROR_CREATOR = "io/ballerina/runtime/api/ErrorCreator";
public static final String RUNTIME_UTILS = "io/ballerina/runtime/internal/util/RuntimeUtils";
public static final String LARGE_STRUCTURE_UTILS = "io/ballerina/runtime/internal/util/LargeStructureUtils";
public static final String OPTION = "io/ballerina/runtime/internal/cli/Option";
public static final String OPERAND = "io/ballerina/runtime/internal/cli/Operand";
public static final String CLI_SPEC = "io/ballerina/runtime/internal/cli/CliSpec";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector;
import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JCast;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JInsKind;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JInstruction;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JLargeArrayInstruction;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JLargeMapInstruction;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JMethodCallInstruction;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JType;
import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags;
Expand Down Expand Up @@ -128,6 +129,7 @@
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ARRAY_VALUE_IMPL;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BAL_ENV_CLASS;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BYTE_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.B_LIST_INITIAL_VALUE_ENTRY;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.B_MAPPING_INITIAL_VALUE_ENTRY;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.B_OBJECT;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.B_STRING_VALUE;
Expand All @@ -137,6 +139,8 @@
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.EQUALS_METHOD;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ERROR_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.FUNCTION_POINTER;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.GET_VALUE_METHOD;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.INSTANTIATE_FUNCTION;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.INT_VALUE;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JSON_UTILS;
Expand Down Expand Up @@ -233,6 +237,7 @@
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PASS_OBJECT_RETURN_OBJECT;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PROCESS_FP_ANNOTATIONS;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PROCESS_OBJ_CTR_ANNOTATIONS;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.RETURN_OBJECT;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SET_DECIMAL_RETURN_DECIMAL;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SET_ON_INIT;
import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.TWO_OBJECTS_ARGS;
Expand Down Expand Up @@ -598,37 +603,85 @@ private BType getSmallestBuiltInUnsignedIntSubTypeContainingTypes(BType lhsType,
}

void generatePlatformIns(JInstruction ins, int localVarOffset) {
if (ins.jKind == JInsKind.JCAST) {
JCast castIns = (JCast) ins;
BType targetType = castIns.targetType;
this.loadVar(castIns.rhsOp.variableDcl);
jvmCastGen.generatePlatformCheckCast(this.mv, this.indexMap, castIns.rhsOp.variableDcl.type, targetType);
this.storeToVar(castIns.lhsOp.variableDcl);
} else if (ins.jKind == JInsKind.CALL) {
JMethodCallInstruction callIns = (JMethodCallInstruction) ins;
boolean isInterface = callIns.invocationType == INVOKEINTERFACE;
int argIndex = 0;
String jMethodVMSig = callIns.jMethodVMSig;
boolean hasBalEnvParam = jMethodVMSig.startsWith(BAL_ENV_PARAM);
if (hasBalEnvParam) {
mv.visitTypeInsn(NEW, BAL_ENV_CLASS);
mv.visitInsn(DUP);
// load the strand
this.mv.visitVarInsn(ALOAD, localVarOffset);
// load the current Module
mv.visitFieldInsn(GETSTATIC, this.moduleInitClass, CURRENT_MODULE_VAR_NAME, GET_MODULE);
mv.visitMethodInsn(INVOKESPECIAL, BAL_ENV_CLASS, JVM_INIT_METHOD,
INIT_BAL_ENV, false);
}
switch (ins.jKind) {
case JCAST -> generateJCastIns((JCast) ins);
case CALL -> generateJMethodCallIns(localVarOffset, (JMethodCallInstruction) ins);
case LARGE_ARRAY -> generateJLargeArrayIns(localVarOffset, (JLargeArrayInstruction) ins);
default -> generateJLargeMapIns(localVarOffset, (JLargeMapInstruction) ins);
}
}

private void generateJLargeMapIns(int localVarOffset, JLargeMapInstruction mapNewIns) {
this.loadVar(mapNewIns.rhsOp.variableDcl);
this.mv.visitVarInsn(ALOAD, localVarOffset);

while (argIndex < callIns.args.size()) {
BIROperand arg = callIns.args.get(argIndex);
this.loadVar(arg.variableDcl);
argIndex += 1;
// load the initial values operand
this.loadVar(mapNewIns.initialValues.variableDcl);
mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, RETURN_OBJECT, false);
mv.visitTypeInsn(CHECKCAST, "[L" + B_MAPPING_INITIAL_VALUE_ENTRY + ";");

this.mv.visitMethodInsn(INVOKEINTERFACE, TYPEDESC_VALUE, INSTANTIATE_FUNCTION, INSTANTIATE, true);
this.storeToVar(mapNewIns.lhsOp.variableDcl);
}

private void generateJLargeArrayIns(int localVarOffset, JLargeArrayInstruction inst) {
BType instType = JvmCodeGenUtil.getReferredType(inst.type);
if (instType.tag == TypeTags.ARRAY) {
this.mv.visitTypeInsn(NEW, ARRAY_VALUE_IMPL);
this.mv.visitInsn(DUP);
jvmTypeGen.loadType(this.mv, inst.type);
loadListInitialValues(inst);
BType elementType = JvmCodeGenUtil.getReferredType(((BArrayType) instType).eType);
if (elementType.tag == TypeTags.RECORD || (elementType.tag == TypeTags.INTERSECTION &&
((BIntersectionType) elementType).effectiveType.tag == TypeTags.RECORD)) {
visitNewRecordArray(elementType);
} else {
this.mv.visitMethodInsn(INVOKESPECIAL, ARRAY_VALUE_IMPL, JVM_INIT_METHOD,
INIT_ARRAY, false);
}
this.mv.visitMethodInsn(callIns.invocationType, callIns.jClassName, callIns.name, jMethodVMSig,
isInterface);
this.storeToVar(inst.lhsOp.variableDcl);
} else {
this.loadVar(inst.typedescOp.variableDcl);
this.mv.visitVarInsn(ALOAD, localVarOffset);
loadListInitialValues(inst);
this.mv.visitMethodInsn(INVOKEINTERFACE, TYPEDESC_VALUE, INSTANTIATE_FUNCTION, INSTANTIATE, true);
this.storeToVar(inst.lhsOp.variableDcl);
}
}

private void generateJMethodCallIns(int localVarOffset, JMethodCallInstruction callIns) {
boolean isInterface = callIns.invocationType == INVOKEINTERFACE;
int argIndex = 0;
String jMethodVMSig = callIns.jMethodVMSig;
boolean hasBalEnvParam = jMethodVMSig.startsWith(BAL_ENV_PARAM);
if (hasBalEnvParam) {
mv.visitTypeInsn(NEW, BAL_ENV_CLASS);
mv.visitInsn(DUP);
// load the strand
this.mv.visitVarInsn(ALOAD, localVarOffset);
// load the current Module
mv.visitFieldInsn(GETSTATIC, this.moduleInitClass, CURRENT_MODULE_VAR_NAME, GET_MODULE);
mv.visitMethodInsn(INVOKESPECIAL, BAL_ENV_CLASS, JVM_INIT_METHOD,
INIT_BAL_ENV, false);
}
while (argIndex < callIns.args.size()) {
BIROperand arg = callIns.args.get(argIndex);
this.loadVar(arg.variableDcl);
argIndex += 1;
}
this.mv.visitMethodInsn(callIns.invocationType, callIns.jClassName, callIns.name, jMethodVMSig,
isInterface);
if (callIns.lhsOp != null) {
this.storeToVar(callIns.lhsOp.variableDcl);
}
}

private void generateJCastIns(JCast castIns) {
BType targetType = castIns.targetType;
this.loadVar(castIns.rhsOp.variableDcl);
jvmCastGen.generatePlatformCheckCast(this.mv, this.indexMap, castIns.rhsOp.variableDcl.type,
targetType);
this.storeToVar(castIns.lhsOp.variableDcl);
}

void generateMoveIns(BIRNonTerminator.Move moveIns) {
Expand Down Expand Up @@ -2174,6 +2227,12 @@ private void loadListInitialValues(BIRNonTerminator.NewArray arrayNewIns) {
}
}

private void loadListInitialValues(JLargeArrayInstruction largeArrayIns) {
this.loadVar(largeArrayIns.values.variableDcl);
mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, RETURN_OBJECT, false);
mv.visitTypeInsn(CHECKCAST, "[L" + B_LIST_INITIAL_VALUE_ENTRY + ";");
}

private void createExprEntry(BIRNode.BIRListConstructorEntry initialValueOp) {
mv.visitTypeInsn(NEW, LIST_INITIAL_EXPRESSION_ENTRY);
mv.visitInsn(DUP);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ public class JvmSignatures {
public static final String HANDLE_WAIT_MULTIPLE = "(L" + MAP + ";L" + MAP_VALUE + ";)V";
public static final String HANDLE_WORKER_ERROR =
"(L" + REF_VALUE + ";L" + STRAND_CLASS + ";[L" + CHANNEL_DETAILS + ";)V";
public static final String HANDLE_OBJECT_LONG_ARGS = "(" + GET_HANDLE_VALUE + GET_OBJECT + "J)V";
public static final String INIT_ARRAY = "(L" + TYPE + ";[L" + B_LIST_INITIAL_VALUE_ENTRY + ";)V";
public static final String INIT_ARRAY_TYPE_IMPL = "(L" + TYPE + ";IZI)V";
public static final String INIT_ARRAY_WITH_INITIAL_VALUES =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public BIROperand[] getRhsOperands() {
return args.toArray(new BIROperand[0]);
}

@Override
public void setRhsOperands(BIROperand[] operands) {
this.args = List.of(operands);
}

@Override
public BIRBasicBlock[] getNextBasicBlocks() {
return new BIRBasicBlock[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public BIROperand[] getRhsOperands() {
return args.toArray(new BIROperand[0]);
}

@Override
public void setRhsOperands(BIROperand[] operands) {
this.args = List.of(operands);
}

@Override
public BIRBasicBlock[] getNextBasicBlocks() {
return new BIRBasicBlock[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
*/
public enum JInsKind {
JCAST((byte) 1),
CALL((byte) 2);
CALL((byte) 2),
LARGE_ARRAY((byte) 3),
LARGE_MAP((byte) 4);

byte value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ public void accept(BIRVisitor visitor) {
public BIROperand[] getRhsOperands() {
return new BIROperand[0];
}

@Override
public void setRhsOperands(BIROperand[] operands) {
// do nothing
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved.
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.ballerinalang.compiler.bir.codegen.interop;

import io.ballerina.tools.diagnostics.Location;
import org.wso2.ballerinalang.compiler.bir.model.BIROperand;
import org.wso2.ballerinalang.compiler.semantics.model.types.BType;

/**
* New large array instruction modeled as BIR NonTerminator JInstruction.
*
* @since 2201.8.0
*/
public class JLargeArrayInstruction extends JInstruction {

public BIROperand typedescOp;
public BIROperand sizeOp;
public BType type;
public BIROperand values;

public JLargeArrayInstruction(Location location, BType type, BIROperand lhsOp, BIROperand sizeOp,
BIROperand values) {
super(location);
jKind = JInsKind.LARGE_ARRAY;
this.type = type;
this.lhsOp = lhsOp;
this.sizeOp = sizeOp;
this.values = values;
}

public JLargeArrayInstruction(Location location, BType type, BIROperand lhsOp, BIROperand typedescOp,
BIROperand sizeOp, BIROperand values) {
this(location, type, lhsOp, sizeOp, values);
this.typedescOp = typedescOp;
}

@Override
public BIROperand[] getRhsOperands() {
if (typedescOp != null) {
return new BIROperand[]{typedescOp, sizeOp, values};
} else {
return new BIROperand[]{sizeOp, values};
}
}

@Override
public void setRhsOperands(BIROperand[] operands) {
if (operands.length == 3) {
this.typedescOp = operands[0];
this.sizeOp = operands[1];
this.values = operands[2];
} else {
this.sizeOp = operands[0];
this.values = operands[1];
}
}
}
Loading

0 comments on commit a9e9d76

Please sign in to comment.