com.facebook.presto.bytecode.instruction.Constant Maven / Gradle / Ivy
/*
* Licensed 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 com.facebook.presto.bytecode.instruction;
import com.facebook.presto.bytecode.BytecodeNode;
import com.facebook.presto.bytecode.BytecodeVisitor;
import com.facebook.presto.bytecode.MethodGenerationContext;
import com.facebook.presto.bytecode.ParameterizedType;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Primitives;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import java.util.List;
import static com.facebook.presto.bytecode.OpCode.ACONST_NULL;
import static com.facebook.presto.bytecode.OpCode.BIPUSH;
import static com.facebook.presto.bytecode.OpCode.DCONST_0;
import static com.facebook.presto.bytecode.OpCode.DCONST_1;
import static com.facebook.presto.bytecode.OpCode.FCONST_0;
import static com.facebook.presto.bytecode.OpCode.FCONST_1;
import static com.facebook.presto.bytecode.OpCode.FCONST_2;
import static com.facebook.presto.bytecode.OpCode.ICONST_0;
import static com.facebook.presto.bytecode.OpCode.ICONST_1;
import static com.facebook.presto.bytecode.OpCode.ICONST_2;
import static com.facebook.presto.bytecode.OpCode.ICONST_3;
import static com.facebook.presto.bytecode.OpCode.ICONST_4;
import static com.facebook.presto.bytecode.OpCode.ICONST_5;
import static com.facebook.presto.bytecode.OpCode.ICONST_M1;
import static com.facebook.presto.bytecode.OpCode.LCONST_0;
import static com.facebook.presto.bytecode.OpCode.LCONST_1;
import static com.facebook.presto.bytecode.OpCode.SIPUSH;
import static com.facebook.presto.bytecode.ParameterizedType.type;
import static com.facebook.presto.bytecode.instruction.FieldInstruction.getStaticInstruction;
import static com.facebook.presto.bytecode.instruction.InvokeInstruction.invokeStatic;
import static com.google.common.base.MoreObjects.toStringHelper;
import static java.util.Objects.requireNonNull;
@SuppressWarnings("UnusedDeclaration")
public abstract class Constant
implements InstructionNode
{
public static Constant loadNull()
{
return new NullConstant();
}
public static Constant loadBoolean(boolean value)
{
return new BooleanConstant(value);
}
public static Constant loadBoxedBoolean(boolean value)
{
return new BoxedBooleanConstant(value);
}
public static Constant loadInt(int value)
{
return new IntConstant(value);
}
public static Constant loadBoxedInt(int value)
{
return new BoxedIntegerConstant(value);
}
public static Constant loadFloat(float value)
{
return new FloatConstant(value);
}
public static Constant loadBoxedFloat(float value)
{
return new BoxedFloatConstant(value);
}
public static Constant loadLong(long value)
{
return new LongConstant(value);
}
public static Constant loadBoxedLong(long value)
{
return new BoxedLongConstant(value);
}
public static Constant loadDouble(double value)
{
return new DoubleConstant(value);
}
public static Constant loadBoxedDouble(double value)
{
return new BoxedDoubleConstant(value);
}
public static Constant loadNumber(Number value)
{
requireNonNull(value, "value is null");
if (value instanceof Byte) {
return loadInt((value).intValue());
}
if (value instanceof Short) {
return loadInt((value).intValue());
}
if (value instanceof Integer) {
return loadInt((Integer) value);
}
if (value instanceof Long) {
return loadLong((Long) value);
}
if (value instanceof Float) {
return loadFloat((Float) value);
}
if (value instanceof Double) {
return loadDouble((Double) value);
}
throw new IllegalStateException("Unsupported number type " + value.getClass().getSimpleName());
}
public static Constant loadString(String value)
{
requireNonNull(value, "value is null");
return new StringConstant(value);
}
public static Constant loadClass(Class> value)
{
requireNonNull(value, "value is null");
return new ClassConstant(type(value));
}
public static Constant loadClass(ParameterizedType value)
{
requireNonNull(value, "value is null");
return new ClassConstant(value);
}
public abstract Object getValue();
@Override
public List getChildNodes()
{
return ImmutableList.of();
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitConstant(parent, this);
}
@Override
public String toString()
{
return toStringHelper(this)
.add("value", getValue())
.toString();
}
public static class NullConstant
extends Constant
{
@Override
public Object getValue()
{
return null;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
visitor.visitInsn(ACONST_NULL.getOpCode());
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitConstant(parent, this);
}
}
public static class BooleanConstant
extends Constant
{
private final boolean value;
private BooleanConstant(boolean value)
{
this.value = value;
}
@Override
public Boolean getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
if (value) {
visitor.visitInsn(ICONST_1.getOpCode());
}
else {
visitor.visitInsn(ICONST_0.getOpCode());
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitBooleanConstant(parent, this);
}
}
public static class BoxedBooleanConstant
extends Constant
{
private final boolean value;
private BoxedBooleanConstant(boolean value)
{
this.value = value;
}
@Override
public Boolean getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
if (value) {
getStaticInstruction(Boolean.class, "TRUE", Boolean.class).accept(visitor, generationContext);
}
else {
getStaticInstruction(Boolean.class, "FALSE", Boolean.class).accept(visitor, generationContext);
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitBoxedBooleanConstant(parent, this);
}
}
public static class IntConstant
extends Constant
{
private final int value;
private IntConstant(int value)
{
this.value = value;
}
@Override
public Integer getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) {
switch (value) {
case -1:
visitor.visitInsn(ICONST_M1.getOpCode());
break;
case 0:
visitor.visitInsn(ICONST_0.getOpCode());
break;
case 1:
visitor.visitInsn(ICONST_1.getOpCode());
break;
case 2:
visitor.visitInsn(ICONST_2.getOpCode());
break;
case 3:
visitor.visitInsn(ICONST_3.getOpCode());
break;
case 4:
visitor.visitInsn(ICONST_4.getOpCode());
break;
case 5:
visitor.visitInsn(ICONST_5.getOpCode());
break;
default:
visitor.visitIntInsn(BIPUSH.getOpCode(), value);
break;
}
}
else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
visitor.visitIntInsn(SIPUSH.getOpCode(), value);
}
else {
visitor.visitLdcInsn(value);
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitIntConstant(parent, this);
}
}
public static class BoxedIntegerConstant
extends Constant
{
private final int value;
private BoxedIntegerConstant(int value)
{
this.value = value;
}
@Override
public Integer getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
loadInt(value).accept(visitor, generationContext);
invokeStatic(Integer.class, "valueOf", Integer.class, int.class).accept(visitor, generationContext);
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitBoxedIntegerConstant(parent, this);
}
}
public static class FloatConstant
extends Constant
{
private final float value;
private FloatConstant(float value)
{
this.value = value;
}
@Override
public Float getValue()
{
return value;
}
@Override
@SuppressWarnings("FloatingPointEquality")
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
// We can not use "value == 0.0" because when value is "-0.0" the expression
// will evaluate to true and we would convert "-0.0" to "0.0" which is
// not the same value
if (Float.floatToIntBits(value) == Float.floatToIntBits(0.0f)) {
visitor.visitInsn(FCONST_0.getOpCode());
}
else if (value == 1.0f) {
visitor.visitInsn(FCONST_1.getOpCode());
}
else if (value == 2.0f) {
visitor.visitInsn(FCONST_2.getOpCode());
}
else {
visitor.visitLdcInsn(value);
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitFloatConstant(parent, this);
}
}
public static class BoxedFloatConstant
extends Constant
{
private final float value;
private BoxedFloatConstant(float value)
{
this.value = value;
}
@Override
public Float getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
loadFloat(value).accept(visitor, generationContext);
invokeStatic(Float.class, "valueOf", Float.class, float.class).accept(visitor, generationContext);
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitBoxedFloatConstant(parent, this);
}
}
public static class LongConstant
extends Constant
{
private final long value;
private LongConstant(long value)
{
this.value = value;
}
@Override
public Long getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
if (value == 0) {
visitor.visitInsn(LCONST_0.getOpCode());
}
else if (value == 1) {
visitor.visitInsn(LCONST_1.getOpCode());
}
else {
visitor.visitLdcInsn(value);
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitLongConstant(parent, this);
}
}
public static class BoxedLongConstant
extends Constant
{
private final long value;
private BoxedLongConstant(long value)
{
this.value = value;
}
@Override
public Long getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
loadLong(value).accept(visitor, generationContext);
invokeStatic(Long.class, "valueOf", Long.class, long.class).accept(visitor, generationContext);
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitBoxedLongConstant(parent, this);
}
}
public static class DoubleConstant
extends Constant
{
private final double value;
private DoubleConstant(double value)
{
this.value = value;
}
@Override
public Double getValue()
{
return value;
}
@Override
@SuppressWarnings("FloatingPointEquality")
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
// We can not use "value == 0.0" because when value is "-0.0" the expression
// will evaluate to true and we would convert "-0.0" to "0.0" which is
// not the same value
if (Double.doubleToLongBits(value) == Double.doubleToLongBits(0.0)) {
visitor.visitInsn(DCONST_0.getOpCode());
}
else if (value == 1.0) {
visitor.visitInsn(DCONST_1.getOpCode());
}
else {
visitor.visitLdcInsn(value);
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitDoubleConstant(parent, this);
}
}
public static class BoxedDoubleConstant
extends Constant
{
private final double value;
private BoxedDoubleConstant(double value)
{
this.value = value;
}
@Override
public Double getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
loadDouble(value).accept(visitor, generationContext);
invokeStatic(Double.class, "valueOf", Double.class, double.class).accept(visitor, generationContext);
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitBoxedDoubleConstant(parent, this);
}
}
public static class StringConstant
extends Constant
{
private final String value;
private StringConstant(String value)
{
this.value = value;
}
@Override
public String getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
visitor.visitLdcInsn(value);
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitStringConstant(parent, this);
}
}
public static class ClassConstant
extends Constant
{
private final ParameterizedType value;
private ClassConstant(ParameterizedType value)
{
this.value = value;
}
@Override
public ParameterizedType getValue()
{
return value;
}
@Override
public void accept(MethodVisitor visitor, MethodGenerationContext generationContext)
{
if (value.isPrimitive()) {
Class> wrapper = Primitives.wrap(value.getPrimitiveType());
getStaticInstruction(wrapper, "TYPE", Class.class).accept(visitor, generationContext);
}
else {
visitor.visitLdcInsn(Type.getType(value.getType()));
}
}
@Override
public T accept(BytecodeNode parent, BytecodeVisitor visitor)
{
return visitor.visitClassConstant(parent, this);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy