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 26 package jdk.nashorn.internal.tools.nasgen; 27 28 import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC; 29 import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; 30 31 import jdk.internal.org.objectweb.asm.Opcodes; 32 import jdk.internal.org.objectweb.asm.Type; 33 import jdk.nashorn.internal.objects.annotations.Where; 34 35 /** 36 * Details about a Java method or field annotated with any of the field/method 37 * annotations from the jdk.nashorn.internal.objects.annotations package. 38 */ 39 public final class MemberInfo implements Cloneable { 40 /** 41 * The different kinds of available class annotations 42 */ 43 public static enum Kind { 44 /** This is a script class */ 45 SCRIPT_CLASS, 46 /** This is a constructor */ 47 CONSTRUCTOR, 48 /** This is a function */ 49 FUNCTION, 50 /** This is a getter */ 51 GETTER, 52 /** This is a setter */ 53 SETTER, 54 /** This is a property */ 55 PROPERTY, 56 /** This is a specialized version of a function */ 57 SPECIALIZED_FUNCTION, 58 /** This is a specialized version of a constructor */ 59 SPECIALIZED_CONSTRUCTOR 60 } 61 62 // keep in sync with jdk.nashorn.internal.objects.annotations.Attribute 63 static final int DEFAULT_ATTRIBUTES = 0x0; 64 65 static final int DEFAULT_ARITY = -2; 66 67 // the kind of the script annotation - one of the above constants 68 private MemberInfo.Kind kind; 69 // script property name 70 private String name; 71 // script property attributes 72 private int attributes; 73 // name of the java member 74 private String javaName; 75 // type descriptor of the java member 76 private String javaDesc; 77 // access bits of the Java field or method 78 private int javaAccess; 79 // initial value for static @Property fields 80 private Object value; 81 // class whose object is created to fill property value 82 private String initClass; 83 // arity of the Function or Constructor 84 private int arity; 85 86 private Where where; 87 88 /** 89 * @return the kind 90 */ 91 public Kind getKind() { 92 return kind; 93 } 94 95 /** 96 * @param kind the kind to set 97 */ 98 public void setKind(final Kind kind) { 99 this.kind = kind; 100 } 101 102 /** 103 * @return the name 104 */ 105 public String getName() { 106 return name; 107 } 108 109 /** 110 * @param name the name to set 111 */ 112 public void setName(final String name) { 113 this.name = name; 114 } 115 116 /** 117 * @return the attributes 118 */ 119 public int getAttributes() { 120 return attributes; 121 } 122 123 /** 124 * @param attributes the attributes to set 125 */ 126 public void setAttributes(final int attributes) { 127 this.attributes = attributes; 128 } 129 130 /** 131 * @return the javaName 132 */ 133 public String getJavaName() { 134 return javaName; 135 } 136 137 /** 138 * @param javaName the javaName to set 139 */ 140 public void setJavaName(final String javaName) { 141 this.javaName = javaName; 142 } 143 144 /** 145 * @return the javaDesc 146 */ 147 public String getJavaDesc() { 148 return javaDesc; 149 } 150 151 void setJavaDesc(final String javaDesc) { 152 this.javaDesc = javaDesc; 153 } 154 155 int getJavaAccess() { 156 return javaAccess; 157 } 158 159 void setJavaAccess(final int access) { 160 this.javaAccess = access; 161 } 162 163 Object getValue() { 164 return value; 165 } 166 167 void setValue(final Object value) { 168 this.value = value; 169 } 170 171 Where getWhere() { 172 return where; 173 } 174 175 void setWhere(final Where where) { 176 this.where = where; 177 } 178 179 boolean isFinal() { 180 return (javaAccess & Opcodes.ACC_FINAL) != 0; 181 } 182 183 boolean isStatic() { 184 return (javaAccess & Opcodes.ACC_STATIC) != 0; 185 } 186 187 boolean isStaticFinal() { 188 return isStatic() && isFinal(); 189 } 190 191 boolean isInstanceGetter() { 192 return kind == Kind.GETTER && where == Where.INSTANCE; 193 } 194 195 /** 196 * Check whether this MemberInfo is a getter that resides in the instance 197 * @return true if instance setter 198 */ 199 boolean isInstanceSetter() { 200 return kind == Kind.SETTER && where == Where.INSTANCE; 201 } 202 203 boolean isInstanceProperty() { 204 return kind == Kind.PROPERTY && where == Where.INSTANCE; 205 } 206 207 boolean isInstanceFunction() { 208 return kind == Kind.FUNCTION && where == Where.INSTANCE; 209 } 210 211 boolean isPrototypeGetter() { 212 return kind == Kind.GETTER && where == Where.PROTOTYPE; 213 } 214 215 boolean isPrototypeSetter() { 216 return kind == Kind.SETTER && where == Where.PROTOTYPE; 217 } 218 219 boolean isPrototypeProperty() { 220 return kind == Kind.PROPERTY && where == Where.PROTOTYPE; 221 } 222 223 boolean isPrototypeFunction() { 224 return kind == Kind.FUNCTION && where == Where.PROTOTYPE; 225 } 226 227 boolean isConstructorGetter() { 228 return kind == Kind.GETTER && where == Where.CONSTRUCTOR; 229 } 230 231 boolean isConstructorSetter() { 232 return kind == Kind.SETTER && where == Where.CONSTRUCTOR; 233 } 234 235 boolean isConstructorProperty() { 236 return kind == Kind.PROPERTY && where == Where.CONSTRUCTOR; 237 } 238 239 boolean isConstructorFunction() { 240 return kind == Kind.FUNCTION && where == Where.CONSTRUCTOR; 241 } 242 243 boolean isConstructor() { 244 return kind == Kind.CONSTRUCTOR; 245 } 246 247 void verify() { 248 if (kind == Kind.CONSTRUCTOR) { 249 final Type returnType = Type.getReturnType(javaDesc); 250 if (! returnType.toString().equals(OBJECT_DESC)) { 251 error("return value should be of Object type, found" + returnType); 252 } 253 final Type[] argTypes = Type.getArgumentTypes(javaDesc); 254 if (argTypes.length < 2) { 255 error("constructor methods should have at least 2 args"); 256 } 257 if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) { 258 error("first argument should be of boolean type, found" + argTypes[0]); 259 } 260 if (! argTypes[1].toString().equals(OBJECT_DESC)) { 261 error("second argument should be of Object type, found" + argTypes[0]); 262 } 263 264 if (argTypes.length > 2) { 265 for (int i = 2; i < argTypes.length - 1; i++) { 266 if (! argTypes[i].toString().equals(OBJECT_DESC)) { 267 error(i + "'th argument should be of Object type, found " + argTypes[i]); 268 } 269 } 270 271 final String lastArgType = argTypes[argTypes.length - 1].toString(); 272 final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); 273 if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { 274 error("last argument is neither Object nor Object[] type: " + lastArgType); 275 } 276 277 if (isVarArg && argTypes.length > 3) { 278 error("vararg constructor has more than 3 arguments"); 279 } 280 } 281 } else if (kind == Kind.FUNCTION) { 282 final Type returnType = Type.getReturnType(javaDesc); 283 if (! returnType.toString().equals(OBJECT_DESC)) { 284 error("return value should be of Object type, found" + returnType); 285 } 286 final Type[] argTypes = Type.getArgumentTypes(javaDesc); 287 if (argTypes.length < 1) { 288 error("function methods should have at least 1 arg"); 289 } 290 if (! argTypes[0].toString().equals(OBJECT_DESC)) { 291 error("first argument should be of Object type, found" + argTypes[0]); 292 } 293 294 if (argTypes.length > 1) { 295 for (int i = 1; i < argTypes.length - 1; i++) { 296 if (! argTypes[i].toString().equals(OBJECT_DESC)) { 297 error(i + "'th argument should be of Object type, found " + argTypes[i]); 298 } 299 } 300 301 final String lastArgType = argTypes[argTypes.length - 1].toString(); 302 final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); 303 if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { 304 error("last argument is neither Object nor Object[] type: " + lastArgType); 305 } 306 307 if (isVarArg && argTypes.length > 2) { 308 error("vararg function has more than 2 arguments"); 309 } 310 } 311 } else if (kind == Kind.GETTER) { 312 final Type[] argTypes = Type.getArgumentTypes(javaDesc); 313 if (argTypes.length != 1) { 314 error("getter methods should have one argument"); 315 } 316 if (! argTypes[0].toString().equals(OBJECT_DESC)) { 317 error("first argument of getter should be of Object type, found: " + argTypes[0]); 318 } 319 if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) { 320 error("return type of getter should not be void"); 321 } 322 } else if (kind == Kind.SETTER) { 323 final Type[] argTypes = Type.getArgumentTypes(javaDesc); 324 if (argTypes.length != 2) { 325 error("setter methods should have two arguments"); 326 } 327 if (! argTypes[0].toString().equals(OBJECT_DESC)) { 328 error("first argument of setter should be of Object type, found: " + argTypes[0]); 329 } 330 if (!Type.getReturnType(javaDesc).toString().equals("V")) { 331 error("return type of setter should be void, found: " + Type.getReturnType(javaDesc)); 332 } 333 } 334 } 335 336 private void error(final String msg) { 337 throw new RuntimeException(javaName + javaDesc + " : " + msg); 338 } 339 340 /** 341 * @return the initClass 342 */ 343 String getInitClass() { 344 return initClass; 345 } 346 347 /** 348 * @param initClass the initClass to set 349 */ 350 void setInitClass(final String initClass) { 351 this.initClass = initClass; 352 } 353 354 @Override 355 protected Object clone() { 356 try { 357 return super.clone(); 358 } catch (final CloneNotSupportedException e) { 359 assert false : "clone not supported " + e; 360 return null; 361 } 362 } 363 364 /** 365 * @return the arity 366 */ 367 int getArity() { 368 return arity; 369 } 370 371 /** 372 * @param arity the arity to set 373 */ 374 void setArity(final int arity) { 375 this.arity = arity; 376 } 377 }