ObjectType.java revision 1068:34ef988d5959
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 private static final long serialVersionUID = 1L; 51 52 protected ObjectType() { 53 this(Object.class); 54 } 55 56 protected ObjectType(final Class<?> clazz) { 57 super("object", 58 clazz, 59 clazz == Object.class ? Type.MAX_WEIGHT : 10, 60 1); 61 } 62 63 @Override 64 public String toString() { 65 return "object" + (getTypeClass() != Object.class ? "<type=" + getTypeClass().getSimpleName() + '>' : ""); 66 } 67 68 @Override 69 public String getShortDescriptor() { 70 return getTypeClass() == Object.class ? "Object" : getTypeClass().getSimpleName(); 71 } 72 73 @Override 74 public Type add(final MethodVisitor method, final int programPoint) { 75 invokestatic(method, ScriptRuntime.ADD); 76 return Type.OBJECT; 77 } 78 79 @Override 80 public Type load(final MethodVisitor method, final int slot) { 81 assert slot != -1; 82 method.visitVarInsn(ALOAD, slot); 83 return this; 84 } 85 86 @Override 87 public void store(final MethodVisitor method, final int slot) { 88 assert slot != -1; 89 method.visitVarInsn(ASTORE, slot); 90 } 91 92 @Override 93 public Type loadUndefined(final MethodVisitor method) { 94 method.visitFieldInsn(GETSTATIC, className(ScriptRuntime.class), "UNDEFINED", typeDescriptor(Undefined.class)); 95 return UNDEFINED; 96 } 97 98 @Override 99 public Type loadForcedInitializer(final MethodVisitor method) { 100 method.visitInsn(ACONST_NULL); 101 // TODO: do we need a special type for null, e.g. Type.NULL? It should be assignable to any other object type 102 // without a checkast in convert. 103 return OBJECT; 104 } 105 106 @Override 107 public Type loadEmpty(final MethodVisitor method) { 108 method.visitFieldInsn(GETSTATIC, className(ScriptRuntime.class), "EMPTY", typeDescriptor(Undefined.class)); 109 return UNDEFINED; 110 } 111 112 @Override 113 public Type ldc(final MethodVisitor method, final Object c) { 114 if (c == null) { 115 method.visitInsn(ACONST_NULL); 116 } else if (c instanceof Undefined) { 117 return loadUndefined(method); 118 } else if (c instanceof String) { 119 method.visitLdcInsn(c); 120 return STRING; 121 } else if (c instanceof Handle) { 122 method.visitLdcInsn(c); 123 return Type.typeFor(MethodHandle.class); 124 } else { 125 throw new UnsupportedOperationException("implementation missing for class " + c.getClass() + " value=" + c); 126 } 127 128 return Type.OBJECT; 129 } 130 131 @Override 132 public Type convert(final MethodVisitor method, final Type to) { 133 final boolean toString = to.isString(); 134 if (!toString) { 135 if (to.isArray()) { 136 final Type elemType = ((ArrayType)to).getElementType(); 137 138 //note that if this an array, things won't work. see {link @ArrayType} subclass. 139 //we also have the unpleasant case of NativeArray which looks like an Object, but is 140 //an array to the type system. This is treated specially at the known load points 141 142 if (elemType.isString()) { 143 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(String[].class)); 144 } else if (elemType.isNumber()) { 145 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(double[].class)); 146 } else if (elemType.isLong()) { 147 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(long[].class)); 148 } else if (elemType.isInteger()) { 149 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(int[].class)); 150 } else { 151 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(Object[].class)); 152 } 153 return to; 154 } else if (to.isObject()) { 155 final Class<?> toClass = to.getTypeClass(); 156 if(!toClass.isAssignableFrom(getTypeClass())) { 157 method.visitTypeInsn(CHECKCAST, CompilerConstants.className(toClass)); 158 } 159 return to; 160 } 161 } else if (isString()) { 162 return to; 163 } 164 165 if (to.isInteger()) { 166 invokestatic(method, JSType.TO_INT32); 167 } else if (to.isNumber()) { 168 invokestatic(method, JSType.TO_NUMBER); 169 } else if (to.isLong()) { 170 invokestatic(method, JSType.TO_LONG); 171 } else if (to.isBoolean()) { 172 invokestatic(method, JSType.TO_BOOLEAN); 173 } else if (to.isString()) { 174 invokestatic(method, JSType.TO_PRIMITIVE_TO_STRING); 175 } else if (to.isCharSequence()) { 176 invokestatic(method, JSType.TO_PRIMITIVE_TO_CHARSEQUENCE); 177 } else { 178 throw new UnsupportedOperationException("Illegal conversion " + this + " -> " + to + " " + isString() + " " + toString); 179 } 180 181 return to; 182 } 183 184 @Override 185 public void _return(final MethodVisitor method) { 186 method.visitInsn(ARETURN); 187 } 188 189 @Override 190 public char getBytecodeStackType() { 191 return 'A'; 192 } 193} 194