MemberInfo.java revision 775:b0bb00872963
1156321Sdamien/* 2156321Sdamien * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3156321Sdamien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4156321Sdamien * 5156321Sdamien * This code is free software; you can redistribute it and/or modify it 6156321Sdamien * under the terms of the GNU General Public License version 2 only, as 7156321Sdamien * published by the Free Software Foundation. Oracle designates this 8156321Sdamien * particular file as subject to the "Classpath" exception as provided 9156321Sdamien * by Oracle in the LICENSE file that accompanied this code. 10156321Sdamien * 11156321Sdamien * This code is distributed in the hope that it will be useful, but WITHOUT 12156321Sdamien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13156321Sdamien * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14156321Sdamien * version 2 for more details (a copy is included in the LICENSE file that 15156321Sdamien * accompanied this code). 16156321Sdamien * 17156321Sdamien * You should have received a copy of the GNU General Public License version 18156321Sdamien * 2 along with this work; if not, write to the Free Software Foundation, 19156321Sdamien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20156321Sdamien * 21156321Sdamien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22156321Sdamien * or visit www.oracle.com if you need additional information or have any 23156321Sdamien * questions. 24156321Sdamien */ 25156321Sdamienpackage jdk.nashorn.internal.tools.nasgen; 26156321Sdamien 27156321Sdamienimport static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC; 28156321Sdamienimport static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; 29156321Sdamienimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC; 30156321Sdamienimport static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC; 31156321Sdamien 32156321Sdamienimport jdk.internal.org.objectweb.asm.Opcodes; 33156321Sdamienimport jdk.internal.org.objectweb.asm.Type; 34156321Sdamienimport jdk.nashorn.internal.objects.annotations.Where; 35156321Sdamienimport jdk.nashorn.internal.runtime.ScriptObject; 36164982Skevlo 37164982Skevlo/** 38156321Sdamien * Details about a Java method or field annotated with any of the field/method 39156321Sdamien * annotations from the jdk.nashorn.internal.objects.annotations package. 40156321Sdamien */ 41156321Sdamienpublic final class MemberInfo implements Cloneable { 42156321Sdamien // class loader of this class 43156321Sdamien private static ClassLoader myLoader = MemberInfo.class.getClassLoader(); 44156321Sdamien 45156321Sdamien /** 46156321Sdamien * The different kinds of available class annotations 47156321Sdamien */ 48156321Sdamien public static enum Kind { 49156321Sdamien 50156321Sdamien /** 51156321Sdamien * This is a script class 52156321Sdamien */ 53156321Sdamien SCRIPT_CLASS, 54156321Sdamien /** 55156321Sdamien * This is a constructor 56156321Sdamien */ 57156321Sdamien CONSTRUCTOR, 58156321Sdamien /** 59156321Sdamien * This is a function 60156321Sdamien */ 61156321Sdamien FUNCTION, 62156321Sdamien /** 63156327Ssilby * This is a getter 64156327Ssilby */ 65156327Ssilby GETTER, 66156327Ssilby /** 67156321Sdamien * This is a setter 68156321Sdamien */ 69156321Sdamien SETTER, 70156321Sdamien /** 71156321Sdamien * This is a property 72156321Sdamien */ 73156321Sdamien PROPERTY, 74156321Sdamien /** 75156321Sdamien * This is a specialized version of a function 76156321Sdamien */ 77156321Sdamien SPECIALIZED_FUNCTION, 78156321Sdamien /** 79156321Sdamien * This is a specialized version of a constructor 80156321Sdamien */ 81156321Sdamien SPECIALIZED_CONSTRUCTOR 82156321Sdamien } 83156321Sdamien 84156321Sdamien // keep in sync with jdk.nashorn.internal.objects.annotations.Attribute 85156321Sdamien static final int DEFAULT_ATTRIBUTES = 0x0; 86156321Sdamien 87156321Sdamien static final int DEFAULT_ARITY = -2; 88156321Sdamien 89156321Sdamien // the kind of the script annotation - one of the above constants 90156321Sdamien private MemberInfo.Kind kind; 91156321Sdamien // script property name 92156321Sdamien private String name; 93156321Sdamien // script property attributes 94156321Sdamien private int attributes; 95156321Sdamien // name of the java member 96156321Sdamien private String javaName; 97156321Sdamien // type descriptor of the java member 98156321Sdamien private String javaDesc; 99156321Sdamien // access bits of the Java field or method 100156321Sdamien private int javaAccess; 101156321Sdamien // initial value for static @Property fields 102156321Sdamien private Object value; 103156321Sdamien // class whose object is created to fill property value 104156321Sdamien private String initClass; 105156321Sdamien // arity of the Function or Constructor 106156321Sdamien private int arity; 107156321Sdamien 108156321Sdamien private Where where; 109156321Sdamien 110156321Sdamien /** 111156321Sdamien * @return the kind 112156321Sdamien */ 113156321Sdamien public Kind getKind() { 114156321Sdamien return kind; 115156321Sdamien } 116156321Sdamien 117156321Sdamien /** 118156321Sdamien * @param kind the kind to set 119156321Sdamien */ 120156321Sdamien public void setKind(final Kind kind) { 121156321Sdamien this.kind = kind; 122156321Sdamien } 123156321Sdamien 124156321Sdamien /** 125156321Sdamien * @return the name 126156321Sdamien */ 127156321Sdamien public String getName() { 128156321Sdamien return name; 129156321Sdamien } 130156321Sdamien 131156321Sdamien /** 132156321Sdamien * @param name the name to set 133156321Sdamien */ 134156321Sdamien public void setName(final String name) { 135156321Sdamien this.name = name; 136156321Sdamien } 137156321Sdamien 138156321Sdamien /** 139156321Sdamien * @return the attributes 140156321Sdamien */ 141156321Sdamien public int getAttributes() { 142156321Sdamien return attributes; 143156321Sdamien } 144156321Sdamien 145156321Sdamien /** 146156321Sdamien * @param attributes the attributes to set 147156321Sdamien */ 148156321Sdamien public void setAttributes(final int attributes) { 149156321Sdamien this.attributes = attributes; 150156321Sdamien } 151156321Sdamien 152156321Sdamien /** 153156321Sdamien * @return the javaName 154156321Sdamien */ 155156321Sdamien public String getJavaName() { 156156321Sdamien return javaName; 157156321Sdamien } 158156321Sdamien 159156321Sdamien /** 160156321Sdamien * @param javaName the javaName to set 161156321Sdamien */ 162156321Sdamien public void setJavaName(final String javaName) { 163156321Sdamien this.javaName = javaName; 164156321Sdamien } 165156321Sdamien 166156321Sdamien /** 167156321Sdamien * @return the javaDesc 168156321Sdamien */ 169156321Sdamien public String getJavaDesc() { 170156321Sdamien return javaDesc; 171156321Sdamien } 172156321Sdamien 173156321Sdamien void setJavaDesc(final String javaDesc) { 174156321Sdamien this.javaDesc = javaDesc; 175156321Sdamien } 176156321Sdamien 177156321Sdamien int getJavaAccess() { 178156321Sdamien return javaAccess; 179156321Sdamien } 180156321Sdamien 181156321Sdamien void setJavaAccess(final int access) { 182156321Sdamien this.javaAccess = access; 183156321Sdamien } 184156321Sdamien 185156321Sdamien Object getValue() { 186156321Sdamien return value; 187156321Sdamien } 188156321Sdamien 189156321Sdamien void setValue(final Object value) { 190156321Sdamien this.value = value; 191156321Sdamien } 192156321Sdamien 193156321Sdamien Where getWhere() { 194156321Sdamien return where; 195156321Sdamien } 196156321Sdamien 197156321Sdamien void setWhere(final Where where) { 198156321Sdamien this.where = where; 199156321Sdamien } 200156321Sdamien 201156321Sdamien boolean isFinal() { 202156321Sdamien return (javaAccess & Opcodes.ACC_FINAL) != 0; 203156321Sdamien } 204156321Sdamien 205156321Sdamien boolean isStatic() { 206156321Sdamien return (javaAccess & Opcodes.ACC_STATIC) != 0; 207156321Sdamien } 208156321Sdamien 209156321Sdamien boolean isStaticFinal() { 210156321Sdamien return isStatic() && isFinal(); 211156321Sdamien } 212156321Sdamien 213156321Sdamien boolean isInstanceGetter() { 214156321Sdamien return kind == Kind.GETTER && where == Where.INSTANCE; 215156321Sdamien } 216156321Sdamien 217156321Sdamien /** 218156321Sdamien * Check whether this MemberInfo is a getter that resides in the instance 219156321Sdamien * 220156321Sdamien * @return true if instance setter 221156321Sdamien */ 222156321Sdamien boolean isInstanceSetter() { 223156321Sdamien return kind == Kind.SETTER && where == Where.INSTANCE; 224156321Sdamien } 225156321Sdamien 226156321Sdamien boolean isInstanceProperty() { 227156321Sdamien return kind == Kind.PROPERTY && where == Where.INSTANCE; 228156321Sdamien } 229156321Sdamien 230156321Sdamien boolean isInstanceFunction() { 231156321Sdamien return kind == Kind.FUNCTION && where == Where.INSTANCE; 232156321Sdamien } 233156321Sdamien 234156321Sdamien boolean isPrototypeGetter() { 235156321Sdamien return kind == Kind.GETTER && where == Where.PROTOTYPE; 236156321Sdamien } 237156321Sdamien 238156321Sdamien boolean isPrototypeSetter() { 239156321Sdamien return kind == Kind.SETTER && where == Where.PROTOTYPE; 240156321Sdamien } 241156321Sdamien 242156321Sdamien boolean isPrototypeProperty() { 243156321Sdamien return kind == Kind.PROPERTY && where == Where.PROTOTYPE; 244156321Sdamien } 245156321Sdamien 246156321Sdamien boolean isPrototypeFunction() { 247156321Sdamien return kind == Kind.FUNCTION && where == Where.PROTOTYPE; 248156321Sdamien } 249156321Sdamien 250156321Sdamien boolean isConstructorGetter() { 251156321Sdamien return kind == Kind.GETTER && where == Where.CONSTRUCTOR; 252156321Sdamien } 253156321Sdamien 254156321Sdamien boolean isConstructorSetter() { 255156321Sdamien return kind == Kind.SETTER && where == Where.CONSTRUCTOR; 256156321Sdamien } 257156321Sdamien 258156321Sdamien boolean isConstructorProperty() { 259156321Sdamien return kind == Kind.PROPERTY && where == Where.CONSTRUCTOR; 260156321Sdamien } 261156321Sdamien 262156321Sdamien boolean isConstructorFunction() { 263156321Sdamien return kind == Kind.FUNCTION && where == Where.CONSTRUCTOR; 264156321Sdamien } 265156321Sdamien 266156321Sdamien boolean isConstructor() { 267156321Sdamien return kind == Kind.CONSTRUCTOR; 268156321Sdamien } 269156321Sdamien 270156321Sdamien void verify() { 271156321Sdamien switch (kind) { 272156321Sdamien case CONSTRUCTOR: { 273156321Sdamien final Type returnType = Type.getReturnType(javaDesc); 274156321Sdamien if (!isJSObjectType(returnType)) { 275156321Sdamien error("return value of a @Constructor method should be of Object type, found " + returnType); 276156321Sdamien } 277156321Sdamien final Type[] argTypes = Type.getArgumentTypes(javaDesc); 278156321Sdamien if (argTypes.length < 2) { 279156321Sdamien error("@Constructor methods should have at least 2 args"); 280156321Sdamien } 281156321Sdamien if (!argTypes[0].equals(Type.BOOLEAN_TYPE)) { 282156321Sdamien error("first argument of a @Constructor method should be of boolean type, found " + argTypes[0]); 283156321Sdamien } 284156321Sdamien if (!isJavaLangObject(argTypes[1])) { 285156321Sdamien error("second argument of a @Constructor method should be of Object type, found " + argTypes[0]); 286156321Sdamien } 287156321Sdamien 288156321Sdamien if (argTypes.length > 2) { 289156321Sdamien for (int i = 2; i < argTypes.length - 1; i++) { 290156321Sdamien if (!isJavaLangObject(argTypes[i])) { 291156321Sdamien error(i + "'th argument of a @Constructor method should be of Object type, found " + argTypes[i]); 292156321Sdamien } 293156321Sdamien } 294156321Sdamien 295156321Sdamien final String lastArgTypeDesc = argTypes[argTypes.length - 1].getDescriptor(); 296156321Sdamien final boolean isVarArg = lastArgTypeDesc.equals(OBJECT_ARRAY_DESC); 297156321Sdamien if (!lastArgTypeDesc.equals(OBJECT_DESC) && !isVarArg) { 298156321Sdamien error("last argument of a @Constructor method is neither Object nor Object[] type: " + lastArgTypeDesc); 299156321Sdamien } 300156321Sdamien 301156321Sdamien if (isVarArg && argTypes.length > 3) { 302156321Sdamien error("vararg of a @Constructor method has more than 3 arguments"); 303156321Sdamien } 304156321Sdamien } 305156321Sdamien } 306156321Sdamien break; 307156321Sdamien case SPECIALIZED_CONSTRUCTOR: { 308156321Sdamien final Type returnType = Type.getReturnType(javaDesc); 309156321Sdamien if (!isJSObjectType(returnType)) { 310156321Sdamien error("return value of a @SpecializedConstructor method should be a valid JS type, found " + returnType); 311156321Sdamien } 312156321Sdamien final Type[] argTypes = Type.getArgumentTypes(javaDesc); 313156321Sdamien for (int i = 0; i < argTypes.length; i++) { 314156407Sdamien if (!isValidJSType(argTypes[i])) { 315156321Sdamien error(i + "'th argument of a @SpecializedConstructor method is not valid JS type, found " + argTypes[i]); 316156407Sdamien } 317156321Sdamien } 318156321Sdamien } 319156321Sdamien break; 320156321Sdamien case FUNCTION: { 321156321Sdamien final Type returnType = Type.getReturnType(javaDesc); 322156321Sdamien if (!isValidJSType(returnType)) { 323156321Sdamien error("return value of a @Function method should be a valid JS type, found " + returnType); 324156321Sdamien } 325156321Sdamien final Type[] argTypes = Type.getArgumentTypes(javaDesc); 326156321Sdamien if (argTypes.length < 1) { 327156321Sdamien error("@Function methods should have at least 1 arg"); 328156321Sdamien } 329156321Sdamien if (!isJavaLangObject(argTypes[0])) { 330156321Sdamien error("first argument of a @Function method should be of Object type, found " + argTypes[0]); 331156321Sdamien } 332156321Sdamien 333156321Sdamien if (argTypes.length > 1) { 334156321Sdamien for (int i = 1; i < argTypes.length - 1; i++) { 335156321Sdamien if (!isJavaLangObject(argTypes[i])) { 336156321Sdamien error(i + "'th argument of a @Function method should be of Object type, found " + argTypes[i]); 337156321Sdamien } 338156321Sdamien } 339156321Sdamien 340156321Sdamien final String lastArgTypeDesc = argTypes[argTypes.length - 1].getDescriptor(); 341156321Sdamien final boolean isVarArg = lastArgTypeDesc.equals(OBJECT_ARRAY_DESC); 342156321Sdamien if (!lastArgTypeDesc.equals(OBJECT_DESC) && !isVarArg) { 343156321Sdamien error("last argument of a @Function method is neither Object nor Object[] type: " + lastArgTypeDesc); 344156321Sdamien } 345156321Sdamien 346156321Sdamien if (isVarArg && argTypes.length > 2) { 347156321Sdamien error("vararg @Function method has more than 2 arguments"); 348156321Sdamien } 349156321Sdamien } 350156321Sdamien } 351156321Sdamien break; 352156321Sdamien case SPECIALIZED_FUNCTION: { 353156321Sdamien final Type returnType = Type.getReturnType(javaDesc); 354156321Sdamien if (!isValidJSType(returnType)) { 355156321Sdamien error("return value of a @SpecializedFunction method should be a valid JS type, found " + returnType); 356156321Sdamien } 357156321Sdamien final Type[] argTypes = Type.getArgumentTypes(javaDesc); 358156321Sdamien for (int i = 0; i < argTypes.length; i++) { 359156321Sdamien if (!isValidJSType(argTypes[i])) { 360156321Sdamien error(i + "'th argument of a @SpecializedFunction method is not valid JS type, found " + argTypes[i]); 361156321Sdamien } 362156321Sdamien } 363156321Sdamien } 364156321Sdamien break; 365156321Sdamien case GETTER: { 366156321Sdamien final Type[] argTypes = Type.getArgumentTypes(javaDesc); 367156321Sdamien if (argTypes.length != 1) { 368156321Sdamien error("@Getter methods should have one argument"); 369156321Sdamien } 370156321Sdamien if (!isJavaLangObject(argTypes[0])) { 371156321Sdamien error("first argument of a @Getter method should be of Object type, found: " + argTypes[0]); 372156321Sdamien } 373156321Sdamien 374156321Sdamien final Type returnType = Type.getReturnType(javaDesc); 375156321Sdamien if (!isJavaLangObject(returnType)) { 376156321Sdamien error("return type of a @Getter method should be Object, found: " + javaDesc); 377156321Sdamien } 378156321Sdamien } 379156321Sdamien break; 380156321Sdamien case SETTER: { 381156321Sdamien final Type[] argTypes = Type.getArgumentTypes(javaDesc); 382156321Sdamien if (argTypes.length != 2) { 383156321Sdamien error("@Setter methods should have two arguments"); 384156321Sdamien } 385156321Sdamien if (!isJavaLangObject(argTypes[0])) { 386156321Sdamien error("first argument of a @Setter method should be of Object type, found: " + argTypes[0]); 387156321Sdamien } 388156321Sdamien if (!Type.getReturnType(javaDesc).toString().equals("V")) { 389156321Sdamien error("return type of of a @Setter method should be void, found: " + Type.getReturnType(javaDesc)); 390156321Sdamien } 391156321Sdamien } 392156321Sdamien break; 393156321Sdamien case PROPERTY: { 394156321Sdamien if (where == Where.CONSTRUCTOR) { 395156321Sdamien if (isStatic()) { 396156321Sdamien if (!isFinal()) { 397156321Sdamien error("static Where.CONSTRUCTOR @Property should be final"); 398156321Sdamien } 399156321Sdamien 400156321Sdamien if (!isJSPrimitiveType(Type.getType(javaDesc))) { 401156321Sdamien error("static Where.CONSTRUCTOR @Property should be a JS primitive"); 402156321Sdamien } 403156321Sdamien } 404156321Sdamien } else if (where == Where.PROTOTYPE) { 405156321Sdamien if (isStatic()) { 406156321Sdamien if (!isFinal()) { 407156321Sdamien error("static Where.PROTOTYPE @Property should be final"); 408156321Sdamien } 409156321Sdamien 410156321Sdamien if (!isJSPrimitiveType(Type.getType(javaDesc))) { 411156321Sdamien error("static Where.PROTOTYPE @Property should be a JS primitive"); 412156321Sdamien } 413156321Sdamien } 414156321Sdamien } 415156321Sdamien } 416156321Sdamien } 417156321Sdamien } 418156321Sdamien 419156321Sdamien private static boolean isValidJSType(final Type type) { 420156321Sdamien return isJSPrimitiveType(type) || isJSObjectType(type); 421156321Sdamien } 422156321Sdamien 423156321Sdamien private static boolean isJSPrimitiveType(final Type type) { 424156321Sdamien switch (type.getSort()) { 425156321Sdamien case Type.BOOLEAN: 426156321Sdamien case Type.INT: 427156321Sdamien case Type.LONG: 428156321Sdamien case Type.DOUBLE: 429156321Sdamien return true; 430156321Sdamien default: 431156321Sdamien return false; 432156321Sdamien } 433156321Sdamien } 434156321Sdamien 435156321Sdamien private static boolean isJSObjectType(final Type type) { 436156321Sdamien return isJavaLangObject(type) || isJavaLangString(type) || isScriptObject(type); 437156321Sdamien } 438156321Sdamien 439156321Sdamien private static boolean isJavaLangObject(final Type type) { 440156321Sdamien return type.getDescriptor().equals(OBJECT_DESC); 441156321Sdamien } 442156321Sdamien 443156321Sdamien private static boolean isJavaLangString(final Type type) { 444156321Sdamien return type.getDescriptor().equals(STRING_DESC); 445156321Sdamien } 446156321Sdamien 447156321Sdamien private static boolean isScriptObject(final Type type) { 448156321Sdamien if (type.getDescriptor().equals(SCRIPTOBJECT_DESC)) { 449156321Sdamien return true; 450156321Sdamien } 451156321Sdamien 452156321Sdamien if (type.getSort() == Type.OBJECT) { 453156321Sdamien try { 454156321Sdamien final Class clazz = Class.forName(type.getClassName(), false, myLoader); 455156321Sdamien return ScriptObject.class.isAssignableFrom(clazz); 456156321Sdamien } catch (final ClassNotFoundException cnfe) { 457156321Sdamien return false; 458156321Sdamien } 459156321Sdamien } 460156321Sdamien 461156321Sdamien return false; 462156321Sdamien } 463156321Sdamien 464156321Sdamien private void error(final String msg) { 465156321Sdamien throw new RuntimeException(javaName + " of type " + javaDesc + " : " + msg); 466156321Sdamien } 467156321Sdamien 468156321Sdamien /** 469156321Sdamien * @return the initClass 470156321Sdamien */ 471156321Sdamien String getInitClass() { 472156321Sdamien return initClass; 473156321Sdamien } 474156321Sdamien 475156321Sdamien /** 476156321Sdamien * @param initClass the initClass to set 477156321Sdamien */ 478156321Sdamien void setInitClass(final String initClass) { 479156321Sdamien this.initClass = initClass; 480156321Sdamien } 481156321Sdamien 482156321Sdamien @Override 483156321Sdamien protected Object clone() { 484156321Sdamien try { 485156321Sdamien return super.clone(); 486156321Sdamien } catch (final CloneNotSupportedException e) { 487156321Sdamien assert false : "clone not supported " + e; 488156321Sdamien return null; 489156321Sdamien } 490156321Sdamien } 491156321Sdamien 492156321Sdamien /** 493156321Sdamien * @return the arity 494156321Sdamien */ 495156321Sdamien int getArity() { 496156321Sdamien return arity; 497156321Sdamien } 498156321Sdamien 499156321Sdamien /** 500156321Sdamien * @param arity the arity to set 501156321Sdamien */ 502156321Sdamien void setArity(final int arity) { 503156321Sdamien this.arity = arity; 504156321Sdamien } 505156321Sdamien} 506156321Sdamien