ObjectType.java revision 953:221a84ef44c0
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.codegen.types; 27 28import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; 29import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 30import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 31import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; 32import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST; 33import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; 34import static jdk.nashorn.internal.codegen.CompilerConstants.className; 35import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; 36 37import java.lang.invoke.MethodHandle; 38import jdk.internal.org.objectweb.asm.Handle; 39import jdk.internal.org.objectweb.asm.MethodVisitor; 40import jdk.nashorn.internal.codegen.CompilerConstants; 41import jdk.nashorn.internal.runtime.JSType; 42import jdk.nashorn.internal.runtime.ScriptRuntime; 43import jdk.nashorn.internal.runtime.Undefined; 44 45/** 46 * Type class: OBJECT This is the object type, used for all object types. It can 47 * contain a class that is a more specialized object 48 */ 49class ObjectType extends Type { 50 51 protected ObjectType() { 52 this(Object.class); 53 } 54 55 protected ObjectType(final Class<?> clazz) { 56 super("object", 57 clazz, 58 clazz == Object.class ? Type.MAX_WEIGHT : 10, 59 1); 60 } 61 62 @Override 63 public String toString() { 64 return "object" + (getTypeClass() != Object.class ? "<type=" + getTypeClass().getSimpleName() + '>' : ""); 65 } 66 67 @Override 68 public String getShortDescriptor() { 69 return getTypeClass() == Object.class ? "Object" : getTypeClass().getSimpleName(); 70 } 71 72 @Override 73 public Type add(final MethodVisitor method, final int programPoint) { 74 invokestatic(method, ScriptRuntime.ADD); 75 return Type.OBJECT; 76 } 77 78 @Override 79 public Type load(final MethodVisitor method, final int slot) { 80 assert slot != -1; 81 method.visitVarInsn(ALOAD, slot); 82 return this; 83 } 84 85 @Override 86 public void store(final MethodVisitor method, final int slot) { 87 assert slot != -1; 88 method.visitVarInsn(ASTORE, slot); 89 } 90 91 @Override 92 public Type loadUndefined(final MethodVisitor method) { 93 method.visitFieldInsn(GETSTATIC, className(ScriptRuntime.class), "UNDEFINED", typeDescriptor(Undefined.class)); 94 return UNDEFINED; 95 } 96 97 @Override 98 public Type loadForcedInitializer(final MethodVisitor method) { 99 method.visitInsn(ACONST_NULL); 100 // TODO: do we need a special type for null, e.g. Type.NULL? It should be assignable to any other object type 101 // without a checkast in convert. 102 return OBJECT; 103 } 104 105 @Override 106 public Type loadEmpty(final MethodVisitor method) { 107 method.visitFieldInsn(GETSTATIC, className(ScriptRuntime.class), "EMPTY", typeDescriptor(Undefined.class)); 108 return UNDEFINED; 109 } 110 111 @Override 112 public Type ldc(final MethodVisitor method, final Object c) { 113 if (c == null) { 114 method.visitInsn(ACONST_NULL); 115 } else if (c instanceof Undefined) { 116 return loadUndefined(method); 117 } else if (c instanceof String) { 118 method.visitLdcInsn(c); 119 return STRING; 120 } else if (c instanceof Handle) { 121 method.visitLdcInsn(c); 122 return Type.typeFor(MethodHandle.class); 123 } else { 124 throw new UnsupportedOperationException("implementation missing for class " + c.getClass() + " value=" + c); 125 } 126 127 return Type.OBJECT; 128 } 129 130 @Override 131 public Type convert(final MethodVisitor method, final Type to) { 132 final boolean toString = to.isString(); 133 if (!toString) { 134 if (to.isArray()) { 135 final Type elemType = ((ArrayType)to).getElementType(); 136 137 //note that if this an array, things won't work. see {link @ArrayType} subclass. 138 //we also have the unpleasant case of NativeArray which looks like an Object, but is 139 //an array to the type system. This is treated specially at the known load points 140 141 if (elemType.isString()) { 142 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(String[].class)); 143 } else if (elemType.isNumber()) { 144 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(double[].class)); 145 } else if (elemType.isLong()) { 146 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(long[].class)); 147 } else if (elemType.isInteger()) { 148 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(int[].class)); 149 } else { 150 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(Object[].class)); 151 } 152 return to; 153 } else if (to.isObject()) { 154 final Class<?> toClass = to.getTypeClass(); 155 if(!toClass.isAssignableFrom(getTypeClass())) { 156 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(toClass)); 157 } 158 return to; 159 } 160 } else if (isString()) { 161 return to; 162 } 163 164 if (to.isInteger()) { 165 invokestatic(method, JSType.TO_INT32); 166 } else if (to.isNumber()) { 167 invokestatic(method, JSType.TO_NUMBER); 168 } else if (to.isLong()) { 169 invokestatic(method, JSType.TO_LONG); 170 } else if (to.isBoolean()) { 171 invokestatic(method, JSType.TO_BOOLEAN); 172 } else if (to.isString()) { 173 invokestatic(method, JSType.TO_PRIMITIVE_TO_STRING); 174 } else if (to.isCharSequence()) { 175 invokestatic(method, JSType.TO_PRIMITIVE_TO_CHARSEQUENCE); 176 } else { 177 throw new UnsupportedOperationException("Illegal conversion " + this + " -> " + to + " " + isString() + " " + toString); 178 } 179 180 return to; 181 } 182 183 @Override 184 public void _return(final MethodVisitor method) { 185 method.visitInsn(ARETURN); 186 } 187 188 @Override 189 public char getBytecodeStackType() { 190 return 'A'; 191 } 192} 193