}
}
@Override
public void compileAssign(MethodVisitor mv, CompileContext compileContext) throws CompileException {
Type valueType = arrayRef.getType().getBaseType();
int currentStack = compileContext.getStackCount();
boolean isTwoWords = (valueType.getNBytes() > 4);
int toPop = 0;
int size = (isTwoWords ? 2 : 1);
// value to be assigned is TOS and will already be coerced to the correct value type
// copy it so we can install the copy and leave the original as a a return value on the stack
if (isTwoWords) {
// [... val1 val2 ==> ... val1 val2 val1 val2]
mv.visitInsn(Opcodes.DUP2);
} else {
// [... val ==> ... val val]
mv.visitInsn(Opcodes.DUP);
}
compileContext.addStackCount(size);
// compile load of array reference -- adds 1 to stack height
arrayRef.compile(mv, compileContext);
// for each index expression compile the expression and the do an array load
Iterator<Expression> iterator = idxList.iterator();
while (iterator.hasNext()) {
Expression idxExpr = iterator.next();
if (iterator.hasNext()) {
// dereference the array to get an embedded array
// compile expression index -- adds 1 to height
idxExpr.compile(mv, compileContext);
// make sure the index is an integer
compileTypeConversion(idxExpr.getType(), Type.I, mv, compileContext);
// fetch embedded array pop 2 and add 1
mv.visitInsn(Opcodes.AALOAD);
compileContext.addStackCount(-1);
valueType = valueType.getBaseType();
} else {
if (isTwoWords) {
// stack is [..., val1, val2, val1, val2, aref ] and we want [..., val1, val2, aref, val1, val2 ]
mv.visitInsn(Opcodes.DUP_X2); // ==> [..., val1, val2, aref. val1, val2, aref ]
compileContext.addStackCount(1);
mv.visitInsn(Opcodes.POP); // ==> [..., val1, val2, aref. val1, val2 ]
compileContext.addStackCount(-1);
} else {
// stack is [..., val, val, aref ] and we want [..., val, aref, val ]
mv.visitInsn(Opcodes.SWAP);
}
// compile expression index -- adds 1 to height
idxExpr.compile(mv, compileContext);
// make sure the index is an integer
compileTypeConversion(idxExpr.getType(), Type.I, mv, compileContext);
if (isTwoWords) {
// stack is [..., val1, val2, aref, val1, val2, idx] and we want [..., val1, val2, aref, idx, val1, val2 ]
mv.visitInsn(Opcodes.DUP_X2); // ==> [..., val1, val2, aref, idx, val1, val2, idx]
compileContext.addStackCount(1);
mv.visitInsn(Opcodes.POP); // ==> [..., val1, val2, aref, idx, val1, val2 ]
compileContext.addStackCount(-1);
} else {
// stack is [..., val, aref, val, idx] and we want [..., val, aref, idx, val ]
mv.visitInsn(Opcodes.SWAP);
}
// now we can do the array store
if (valueType.isObject() || valueType.isArray()) {
// compile load object - pops 3
mv.visitInsn(Opcodes.AASTORE);
toPop =- 3;
} else if (valueType == Type.Z || valueType == Type.B) {
// compile load byte - pops 3
mv.visitInsn(Opcodes.BASTORE);
toPop = -3;
} else if (valueType == Type.S) {
// compile load short - pops 3
mv.visitInsn(Opcodes.SASTORE);
toPop = -3;
} else if (valueType == Type.C) {
// compile load char - pops 3
mv.visitInsn(Opcodes.CASTORE);
toPop = -3;
} else if (valueType == Type.I) {
// compile load int - pops 3
mv.visitInsn(Opcodes.IASTORE);
toPop = -3;
} else if (valueType == Type.J) {
// compile load long - pops 4
mv.visitInsn(Opcodes.LASTORE);
toPop = -4;
} else if (valueType == Type.F) {
// compile load float - pops 3
mv.visitInsn(Opcodes.FASTORE);
toPop = -3;
} else if (valueType == Type.D) {
// compile load double - pops 4
mv.visitInsn(Opcodes.DASTORE);
toPop = -4;
}
compileContext.addStackCount(toPop);
if (iterator.hasNext()) {
assert valueType.isArray();
valueType =valueType.getBaseType();
}
}
}
// check stack height