diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java index c02f1e591ca..31564b1966a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java @@ -28,27 +28,33 @@ import java.util.Set; public class BoxedBasicValue extends BasicValue { private final Set associatedInsns = new HashSet(); - private final AbstractInsnNode boxingInsn; + private final Set associatedVariables = new HashSet(); + private final Set mergedWith = new HashSet(); private final Type primitiveType; - private boolean wasUnboxed = false; + private boolean isSafeToRemove = true; - public BoxedBasicValue(Type primitiveType, AbstractInsnNode insnNode) { - super(AsmUtil.boxType(primitiveType)); - this.primitiveType = primitiveType; + public BoxedBasicValue(Type boxedType, AbstractInsnNode insnNode) { + super(boxedType); + this.primitiveType = AsmUtil.unboxType(boxedType); associatedInsns.add(insnNode); - boxingInsn = insnNode; } @Override public boolean equals(Object o) { - if (this == o) return true; + return this == o; + } + + public boolean typeEquals(Object o) { if (o == null || getClass() != o.getClass()) return false; BoxedBasicValue that = (BoxedBasicValue) o; - if (!getType().equals(that.getType())) return false; + return getType().equals(that.getType()); + } - return (boxingInsn == ((BoxedBasicValue) o).boxingInsn); + @Override + public int hashCode() { + return System.identityHashCode(this); } public List getAssociatedInsns() { @@ -59,15 +65,50 @@ public class BoxedBasicValue extends BasicValue { associatedInsns.add(insnNode); } + public void addVariableIndex(int index) { + associatedVariables.add(index); + } + + public List getVariablesIndexes() { + return new ArrayList(associatedVariables); + } + public Type getPrimitiveType() { return primitiveType; } - public boolean wasUnboxed() { - return wasUnboxed; + public void mergeWith(BoxedBasicValue value) { + if (this == value) { + return; + } + + if (!value.isSafeToRemove) { + propagateRemovingAsUnsafe(); + } + + if (!isSafeToRemove) { + value.propagateRemovingAsUnsafe(); + } + + mergedWith.add(value); + value.mergedWith.add(this); } - public void setWasUnboxed(boolean wasUnboxed) { - this.wasUnboxed = wasUnboxed; + public void propagateRemovingAsUnsafe() { + isSafeToRemove = false; + + for (BoxedBasicValue value : mergedWith) { + if (value.isSafeToRemove()) { + value.propagateRemovingAsUnsafe(); + } + } + } + + public boolean isSafeToRemove() { + return isSafeToRemove; + } + + public boolean isDoubleSize() { + return getPrimitiveType().getSize() == 2; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java index a802c84e8fe..e730d0e64ad 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java @@ -94,7 +94,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { if (isBoxing(insn)) { int index = insnList.indexOf(insn); if (!boxingPlaces.containsKey(index)) { - BoxedBasicValue boxedBasicValue = new BoxedBasicValue(values.get(0).getType(), insn); + BoxedBasicValue boxedBasicValue = new BoxedBasicValue(value.getType(), insn); onNewBoxedValue(boxedBasicValue); boxingPlaces.put(index, boxedBasicValue); } @@ -105,9 +105,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { values.get(0) instanceof BoxedBasicValue && value.getType().equals(((BoxedBasicValue) values.get(0)).getPrimitiveType())) { - BoxedBasicValue boxedBasicValue = (BoxedBasicValue) values.get(0); - boxedBasicValue.addInsn(insn); - boxedBasicValue.setWasUnboxed(true); + onUnboxing((BoxedBasicValue) values.get(0), insn); } else { for (BasicValue arg : values) { @@ -120,12 +118,10 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { return value; } - @Override @Nullable public BasicValue unaryOperation(@NotNull AbstractInsnNode insn, @NotNull BasicValue value) throws AnalyzerException { - if (isAllowedUnaryOperationWithBoxed(insn.getOpcode()) && value instanceof BoxedBasicValue) { - ((BoxedBasicValue) value).addInsn(insn); + if (insn.getOpcode() == Opcodes.CHECKCAST && value instanceof BoxedBasicValue) { return value; } @@ -135,7 +131,8 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { @Override @NotNull public BasicValue merge(@NotNull BasicValue v, @NotNull BasicValue w) { - if (v instanceof BoxedBasicValue && v.equals(w)) { + if (v instanceof BoxedBasicValue && ((BoxedBasicValue) v).typeEquals(w)) { + ((BoxedBasicValue) v).mergeWith((BoxedBasicValue) w); return v; } @@ -153,19 +150,19 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { } - protected void onNewBoxedValue(BoxedBasicValue value) { + protected void onNewBoxedValue(@NotNull BoxedBasicValue value) { } - protected void onMethodCallWithBoxedValue(BoxedBasicValue value) { + protected void onUnboxing(@NotNull BoxedBasicValue value, @NotNull AbstractInsnNode insn) { } - protected void onMergeFail(BoxedBasicValue value) { + protected void onMethodCallWithBoxedValue(@NotNull BoxedBasicValue value) { } - protected boolean isAllowedUnaryOperationWithBoxed(int opcode) { - return opcode == Opcodes.CHECKCAST || opcode == Opcodes.IFNULL; + protected void onMergeFail(@NotNull BoxedBasicValue value) { + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java index 76ba4c92ae3..8f6d4675586 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java @@ -22,12 +22,11 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.org.objectweb.asm.Opcodes; import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; import org.jetbrains.org.objectweb.asm.tree.InsnList; +import org.jetbrains.org.objectweb.asm.tree.VarInsnNode; import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException; import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; -import java.util.ArrayList; import java.util.HashSet; -import java.util.List; import java.util.Set; class RedundantBoxingInterpreter extends BoxingInterpreter { @@ -36,7 +35,8 @@ class RedundantBoxingInterpreter extends BoxingInterpreter { static { ImmutableSet.Builder unsafeOperationsOpcodesBuilder = ImmutableSet.builder(); unsafeOperationsOpcodesBuilder.add( - Opcodes.AASTORE, Opcodes.PUTFIELD, Opcodes.PUTSTATIC, Opcodes.ARETURN + Opcodes.AASTORE, Opcodes.PUTFIELD, Opcodes.PUTSTATIC, Opcodes.ARETURN, + Opcodes.IFNONNULL, Opcodes.IFNULL, Opcodes.IF_ACMPEQ, Opcodes.IF_ACMPNE ); unsafeOperationsOpcodes = unsafeOperationsOpcodesBuilder.build(); @@ -48,9 +48,24 @@ class RedundantBoxingInterpreter extends BoxingInterpreter { super(insnList); } - private void checkIfUnsafeOperationWithBoxed(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) { - if (value instanceof BoxedBasicValue && unsafeOperationsOpcodes.contains(insnNode.getOpcode())) { - markAsDirty((BoxedBasicValue) value); + private static void markValueAsDirty(@NotNull BoxedBasicValue value) { + value.propagateRemovingAsUnsafe(); + } + + private static void addAssociatedInsn(@NotNull BoxedBasicValue value, @NotNull AbstractInsnNode insn) { + if (value.isSafeToRemove()) { + value.addInsn(insn); + } + } + + private static void processOperationWithBoxedValue(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) { + if (value instanceof BoxedBasicValue) { + if (unsafeOperationsOpcodes.contains(insnNode.getOpcode())) { + markValueAsDirty((BoxedBasicValue) value); + } + else { + addAssociatedInsn((BoxedBasicValue) value, insnNode); + } } } @@ -61,7 +76,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter { @NotNull BasicValue value2 ) throws AnalyzerException { - checkIfUnsafeOperationWithBoxed(value2, insn); + processOperationWithBoxedValue(value2, insn); return super.binaryOperation(insn, value1, value2); } @@ -72,57 +87,59 @@ class RedundantBoxingInterpreter extends BoxingInterpreter { @NotNull BasicValue value1, @NotNull BasicValue value2, @NotNull BasicValue value3 ) throws AnalyzerException { - checkIfUnsafeOperationWithBoxed(value3, insn); + processOperationWithBoxedValue(value3, insn); return super.ternaryOperation(insn, value1, value2, value3); } + @Nullable @Override - protected boolean isAllowedUnaryOperationWithBoxed(int opcode) { - return opcode == Opcodes.CHECKCAST; + public BasicValue unaryOperation( + @NotNull AbstractInsnNode insn, @NotNull BasicValue value + ) throws AnalyzerException { + + processOperationWithBoxedValue(value, insn); + + return super.unaryOperation(insn, value); } @Override @NotNull public BasicValue copyOperation(@NotNull AbstractInsnNode insn, @NotNull BasicValue value) throws AnalyzerException { - // currently we don't allow any copy operations with boxed values - if (value instanceof BoxedBasicValue) { - markAsDirty((BoxedBasicValue) value); - return new BasicValue(value.getType()); + if (value instanceof BoxedBasicValue && insn.getOpcode() == Opcodes.ASTORE) { + ((BoxedBasicValue) value).addVariableIndex(((VarInsnNode) insn).var); } + processOperationWithBoxedValue(value, insn); + return super.copyOperation(insn, value); } + @Override - protected void onNewBoxedValue(BoxedBasicValue value) { + protected void onNewBoxedValue(@NotNull BoxedBasicValue value) { candidatesBoxedValues.add(value); } - private void markAsDirty(BoxedBasicValue value) { - candidatesBoxedValues.remove(value); + @Override + protected void onUnboxing( + @NotNull BoxedBasicValue value, @NotNull AbstractInsnNode insn + ) { + addAssociatedInsn(value, insn); } @Override - protected void onMethodCallWithBoxedValue(BoxedBasicValue value) { - markAsDirty(value); + protected void onMethodCallWithBoxedValue(@NotNull BoxedBasicValue value) { + markValueAsDirty(value); } @Override - protected void onMergeFail(BoxedBasicValue v) { - markAsDirty(v); + protected void onMergeFail(@NotNull BoxedBasicValue v) { + markValueAsDirty(v); } @NotNull - public List getCandidatesBoxedValues() { - List result = new ArrayList(); - - for (BoxedBasicValue value : candidatesBoxedValues) { - if (value.wasUnboxed()) { - result.add(value); - } - } - - return result; + public Set getCandidatesBoxedValues() { + return candidatesBoxedValues; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java index 1f18f6212d3..ddaab67972d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingMethodTransformer.java @@ -16,14 +16,19 @@ package org.jetbrains.jet.codegen.optimization.boxing; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.codegen.optimization.transformer.MethodTransformer; -import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; -import org.jetbrains.org.objectweb.asm.tree.MethodNode; +import org.jetbrains.org.objectweb.asm.Opcodes; +import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.tree.*; import org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer; import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; +import org.jetbrains.org.objectweb.asm.tree.analysis.Frame; -import java.util.List; +import java.util.HashSet; +import java.util.Set; public class RedundantBoxingMethodTransformer extends MethodTransformer { public RedundantBoxingMethodTransformer(MethodTransformer methodTransformer) { @@ -32,21 +37,280 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer { @Override public void transform(@NotNull String owner, @NotNull MethodNode node) { - for (BoxedBasicValue value : analyze(owner, node)) { - for (AbstractInsnNode insnNode : value.getAssociatedInsns()) { - node.instructions.remove(insnNode); - } + RedundantBoxingInterpreter interpreter = new RedundantBoxingInterpreter(node.instructions); + Analyzer analyzer = new Analyzer(interpreter); + + Frame[] frames = runAnalyzer(analyzer, owner, node); + Set valuesToOptimize = filterSafeToRemoveValues(interpreter.getCandidatesBoxedValues()); + + if (valuesToOptimize.size() > 0) { + findValuesClashingWithVariables(node, frames); + + valuesToOptimize = filterSafeToRemoveValues(valuesToOptimize); + + adaptLocalVariableTableForBoxedValues(node, frames); + + int[] remapping = variablesRemapping(valuesToOptimize, node); + applyVariablesRemapping(node, remapping); + + adaptInstructionsForBoxedValues(node, frames, valuesToOptimize); } super.transform(owner, node); } - private static List analyze(@NotNull String owner, @NotNull MethodNode node) { - RedundantBoxingInterpreter interpreter = new RedundantBoxingInterpreter(node.instructions); - Analyzer analyzer = new Analyzer(interpreter); + @NotNull + private static Set filterSafeToRemoveValues(@NotNull Set values) { + return new HashSet(Collections2.filter(values, new Predicate() { + @Override + public boolean apply(BoxedBasicValue input) { + return input.isSafeToRemove(); + } + })); + } - runAnalyzer(analyzer, owner, node); + private static void adaptLocalVariableTableForBoxedValues(@NotNull MethodNode node, @NotNull Frame[] frames) { + for (LocalVariableNode localVariableNode : node.localVariables) { + if (Type.getType(localVariableNode.desc).getSort() != Type.OBJECT) { + continue; + } - return interpreter.getCandidatesBoxedValues(); + adaptLocalVariableTableEntryForBoxedValues(node, frames, localVariableNode); + } + } + + private static void adaptLocalVariableTableEntryForBoxedValues( + @NotNull MethodNode node, @NotNull Frame[] frames, @NotNull LocalVariableNode localVariableNode + ) { + InsnList insnList = node.instructions; + int from = insnList.indexOf(localVariableNode.start) + 1; + int to = insnList.indexOf(localVariableNode.end) - 1; + + for (int i = from; i <= to; i++) { + AbstractInsnNode insn = insnList.get(i); + if (insn.getOpcode() == Opcodes.ASTORE && ((VarInsnNode) insn).var == localVariableNode.index) { + if (frames[i] == null) { + return; + } + + BasicValue top = frames[i].getStack(frames[i].getStackSize() - 1); + if (!(top instanceof BoxedBasicValue) || !((BoxedBasicValue) top).isSafeToRemove()) { + return; + } + + localVariableNode.desc = ((BoxedBasicValue) top).getPrimitiveType().getDescriptor(); + + return; + } + } + } + + private static void findValuesClashingWithVariables( + @NotNull MethodNode node, @NotNull Frame[] frames + ) { + + while (findValuesClashingWithVariablesIteration(node, frames)) { + } + } + + private static boolean findValuesClashingWithVariablesIteration( + @NotNull MethodNode node, @NotNull Frame[] frames + ) { + InsnList insnList = node.instructions; + boolean needToRepeat = false; + + for (LocalVariableNode localVariableNode : node.localVariables) { + if (Type.getType(localVariableNode.desc).getSort() != Type.OBJECT) { + continue; + } + + int index = localVariableNode.index; + int from = insnList.indexOf(localVariableNode.start) + 1; + int to = insnList.indexOf(localVariableNode.end) - 1; + + if (isThereUnsafeStoreInstruction(insnList, frames, from, to, index)) { + needToRepeat |= markAllBoxedValuesStoredAsUnsafeToRemove(insnList, frames, from, to, index); + } + } + + return needToRepeat; + } + + /** + * Check if there are unsafe ASTORE instructions, that put into var something but boxed values of the same type + * + * @param insnList + * @param frames + * @param from + * @param to + * @param varIndex + * @return + */ + private static boolean isThereUnsafeStoreInstruction( + @NotNull InsnList insnList, + @NotNull Frame[] frames, + int from, int to, int varIndex + ) { + Type usedAsType = null; + + for (int i = from; i <= to; i++) { + AbstractInsnNode insn = insnList.get(i); + if (insn.getOpcode() == Opcodes.ASTORE && ((VarInsnNode) insn).var == varIndex) { + if (frames[i] == null) { + return true; + } + + BasicValue top = frames[i].getStack(frames[i].getStackSize() - 1); + if (!(top instanceof BoxedBasicValue) || !((BoxedBasicValue) top).isSafeToRemove()) { + return true; + } + + if (usedAsType == null) { + usedAsType = ((BoxedBasicValue) top).getPrimitiveType(); + } + + if (!usedAsType.equals(((BoxedBasicValue) top).getPrimitiveType())) { + return true; + } + } + } + + return false; + } + + private static boolean markAllBoxedValuesStoredAsUnsafeToRemove( + @NotNull InsnList insnList, + @NotNull Frame[] frames, + int from, int to, int varIndex + ) { + boolean wasChanges = false; + + for (int i = from; i <= to; i++) { + AbstractInsnNode insn = insnList.get(i); + if (insn.getOpcode() == Opcodes.ASTORE && ((VarInsnNode) insn).var == varIndex) { + if (frames[i] == null) { + continue; + } + + BasicValue top = frames[i].getStack(frames[i].getStackSize() - 1); + if (!(top instanceof BoxedBasicValue) || !((BoxedBasicValue) top).isSafeToRemove()) { + continue; + } + + wasChanges |= true; + ((BoxedBasicValue) top).propagateRemovingAsUnsafe(); + } + } + + return wasChanges; + } + + @NotNull + private static int[] variablesRemapping(@NotNull Iterable values, @NotNull MethodNode node) { + Set longTypesVars = new HashSet(); + for (BoxedBasicValue value : values) { + if (value.getPrimitiveType().getSize() == 2) { + longTypesVars.addAll(value.getVariablesIndexes()); + } + } + + node.maxLocals += longTypesVars.size(); + int[] remapping = new int[node.maxLocals]; + for (int i = 0; i < remapping.length; i++) { + remapping[i] = i; + } + + for (int longVarIndex : longTypesVars) { + for (int i = longVarIndex + 1; i < remapping.length; i++) { + remapping[i]++; + } + } + + return remapping; + } + + private static void applyVariablesRemapping(@NotNull MethodNode node, @NotNull int[] remapping) { + for (AbstractInsnNode insn : node.instructions.toArray()) { + if (insn instanceof VarInsnNode) { + ((VarInsnNode) insn).var = remapping[((VarInsnNode) insn).var]; + } + if (insn instanceof IincInsnNode) { + ((IincInsnNode) insn).var = remapping[((IincInsnNode) insn).var]; + } + } + + for (LocalVariableNode localVariableNode : node.localVariables) { + localVariableNode.index = remapping[localVariableNode.index]; + } + } + + private static void adaptInstructionsForBoxedValues( + @NotNull MethodNode node, @NotNull Frame[] frames, @NotNull Set values + ) { + collectPopInstructionsForBoxedValues(node, frames); + + for (BoxedBasicValue value : values) { + adaptInstructionsForBoxedValue(node, value); + } + } + + private static void collectPopInstructionsForBoxedValues( + @NotNull MethodNode node, @NotNull Frame[] frames + ) { + for (int i = 0; i < node.instructions.size(); i++) { + AbstractInsnNode insn = node.instructions.get(i); + if (insn.getOpcode() != Opcodes.POP || frames[i] == null) { + continue; + } + + BasicValue top = frames[i].getStack(frames[i].getStackSize() - 1); + if (top instanceof BoxedBasicValue && ((BoxedBasicValue) top).isSafeToRemove()) { + ((BoxedBasicValue) top).addInsn(node.instructions.get(i)); + } + } + } + + private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedBasicValue value) { + for (AbstractInsnNode insn : value.getAssociatedInsns()) { + adaptInstruction(node, insn, value); + } + } + + private static void adaptInstruction( + @NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedBasicValue value + ) { + boolean isDoubleSize = value.isDoubleSize(); + + switch (insn.getOpcode()) { + case Opcodes.POP: + if (isDoubleSize) { + node.instructions.set( + insn, + new InsnNode(Opcodes.POP2) + ); + } + break; + case Opcodes.DUP: + if (isDoubleSize) { + node.instructions.set( + insn, + new InsnNode(Opcodes.DUP2) + ); + } + break; + case Opcodes.ASTORE: + case Opcodes.ALOAD: + int intVarOpcode = insn.getOpcode() == Opcodes.ASTORE ? Opcodes.ISTORE : Opcodes.ILOAD; + node.instructions.set( + insn, + new VarInsnNode( + value.getPrimitiveType().getOpcode(intVarOpcode), + ((VarInsnNode) insn).var + ) + ); + break; + default: + node.instructions.remove(insn); + } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/common/OptimizationBasicInterpreter.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/common/OptimizationBasicInterpreter.java index 80fea224f59..a1eda689cc2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/common/OptimizationBasicInterpreter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/common/OptimizationBasicInterpreter.java @@ -28,6 +28,10 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; public class OptimizationBasicInterpreter extends BasicInterpreter { private static final BasicValue MIXED_VALUE = new BasicValue(Type.getObjectType("#")); + private static final BasicValue BOOLEAN_VALUE = new BasicValue(Type.BOOLEAN_TYPE); + private static final BasicValue CHAR_VALUE = new BasicValue(Type.CHAR_TYPE); + private static final BasicValue BYTE_VALUE = new BasicValue(Type.BYTE_TYPE); + private static final BasicValue SHORT_VALUE = new BasicValue(Type.SHORT_TYPE); @Override @Nullable @@ -35,11 +39,23 @@ public class OptimizationBasicInterpreter extends BasicInterpreter { if (type == null) { return super.newValue(null); } - if (type.getSort() == Type.OBJECT) { - return new BasicValue(type); - } - return super.newValue(type); + switch (type.getSort()) { + case Type.VOID: + return null; + case Type.BOOLEAN: + return BOOLEAN_VALUE; + case Type.CHAR: + return CHAR_VALUE; + case Type.BYTE: + return BYTE_VALUE; + case Type.SHORT: + return SHORT_VALUE; + case Type.OBJECT: + return new BasicValue(type); + default: + return super.newValue(type); + } } @Override