src/jdk/nashorn/internal/runtime/UserAccessorProperty.java

Mon, 17 Mar 2014 18:02:00 +0530

author
sundar
date
Mon, 17 Mar 2014 18:02:00 +0530
changeset 771
5ab19753ce4a
parent 489
dd79c04ef7df
child 828
e0e2d72e6699
permissions
-rw-r--r--

8037400: Remove getInitialMap getters and GlobalObject interface
Reviewed-by: lagergren, jlaskey, attila

     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  */
    26 package jdk.nashorn.internal.runtime;
    28 import java.lang.invoke.MethodHandle;
    29 import java.lang.invoke.MethodHandles;
    30 import java.util.concurrent.Callable;
    32 import jdk.nashorn.internal.codegen.CompilerConstants;
    33 import jdk.nashorn.internal.lookup.Lookup;
    34 import jdk.nashorn.internal.runtime.linker.Bootstrap;
    36 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
    37 import jdk.nashorn.internal.objects.Global;
    38 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    39 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    41 /**
    42  * Property with user defined getters/setters. Actual getter and setter
    43  * functions are stored in underlying ScriptObject. Only the 'slot' info is
    44  * stored in the property.
    45  *
    46  * The slots here denote either ScriptObject embed field number or spill
    47  * array index. For spill array index, we use slot value of
    48  * (index + ScriptObject.embedSize). See also ScriptObject.getEmbedOrSpill
    49  * method. Negative slot value means that the corresponding getter or setter
    50  * is null. Note that always two slots are allocated in ScriptObject - but
    51  * negative (less by 1) slot number is stored for null getter or setter.
    52  * This is done so that when the property is redefined with a different
    53  * getter and setter (say, both non-null), we'll have spill slots to store
    54  * those. When a slot is negative, (-slot - 1) is the embed/spill index.
    55  */
    56 public final class UserAccessorProperty extends Property {
    58     /** User defined getter function slot. */
    59     private final int getterSlot;
    61     /** User defined setter function slot. */
    62     private final int setterSlot;
    64     /** Getter method handle */
    65     private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
    66             "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class);
    68     /** Setter method handle */
    69     private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
    70             "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class);
    72     /** Dynamic invoker for getter */
    73     private static final Object INVOKE_UA_GETTER = new Object();
    75     private static MethodHandle getINVOKE_UA_GETTER() {
    77         return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER,
    78                 new Callable<MethodHandle>() {
    79                     @Override
    80                     public MethodHandle call() {
    81                         return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
    82                             Object.class, Object.class);
    83                     }
    84                 });
    85     }
    87     /** Dynamic invoker for setter */
    88     private static Object INVOKE_UA_SETTER = new Object();
    89     private static MethodHandle getINVOKE_UA_SETTER() {
    90         return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER,
    91                 new Callable<MethodHandle>() {
    92                     @Override
    93                     public MethodHandle call() {
    94                         return Bootstrap.createDynamicInvoker("dyn:call", void.class,
    95                             Object.class, Object.class, Object.class);
    96                     }
    97                 });
    98     }
   100     /**
   101      * Constructor
   102      *
   103      * @param key        property key
   104      * @param flags      property flags
   105      * @param getterSlot getter slot, starting at first embed
   106      * @param setterSlot setter slot, starting at first embed
   107      */
   108     UserAccessorProperty(final String key, final int flags, final int getterSlot, final int setterSlot) {
   109         super(key, flags, -1);
   110         this.getterSlot = getterSlot;
   111         this.setterSlot = setterSlot;
   112     }
   114     private UserAccessorProperty(final UserAccessorProperty property) {
   115         super(property);
   116         this.getterSlot = property.getterSlot;
   117         this.setterSlot = property.setterSlot;
   118     }
   120     /**
   121      * Return getter spill slot for this UserAccessorProperty.
   122      * @return getter slot
   123      */
   124     public int getGetterSlot() {
   125         return getterSlot;
   126     }
   128     /**
   129      * Return setter spill slot for this UserAccessorProperty.
   130      * @return setter slot
   131      */
   132     public int getSetterSlot() {
   133         return setterSlot;
   134     }
   136     @Override
   137     protected Property copy() {
   138         return new UserAccessorProperty(this);
   139     }
   141     @Override
   142     public boolean equals(final Object other) {
   143         if (!super.equals(other)) {
   144             return false;
   145         }
   147         final UserAccessorProperty uc = (UserAccessorProperty) other;
   148         return getterSlot == uc.getterSlot && setterSlot == uc.setterSlot;
   149     }
   151     @Override
   152     public int hashCode() {
   153         return super.hashCode() ^ getterSlot ^ setterSlot;
   154     }
   156     /*
   157      * Accessors.
   158      */
   159     @Override
   160     public int getSpillCount() {
   161         return 2;
   162     }
   164     @Override
   165     public boolean hasGetterFunction(final ScriptObject obj) {
   166         return obj.getSpill(getterSlot) != null;
   167     }
   169     @Override
   170     public boolean hasSetterFunction(final ScriptObject obj) {
   171         return obj.getSpill(setterSlot) != null;
   172     }
   174     @Override
   175     public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
   176         return userAccessorGetter(owner, getGetterSlot(), self);
   177     }
   179     @Override
   180     public void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
   181         userAccessorSetter(owner, getSetterSlot(), strict ? getKey() : null, self, value);
   182     }
   184     @Override
   185     public MethodHandle getGetter(final Class<?> type) {
   186         return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type);
   187     }
   189     @Override
   190     public ScriptFunction getGetterFunction(final ScriptObject obj) {
   191         final Object value = obj.getSpill(getterSlot);
   192         return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
   193     }
   195     @Override
   196     public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
   197         return USER_ACCESSOR_SETTER.methodHandle();
   198     }
   200     @Override
   201     public ScriptFunction getSetterFunction(final ScriptObject obj) {
   202         final Object value = obj.getSpill(setterSlot);
   203         return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
   204     }
   206     // User defined getter and setter are always called by "dyn:call". Note that the user
   207     // getter/setter may be inherited. If so, proto is bound during lookup. In either
   208     // inherited or self case, slot is also bound during lookup. Actual ScriptFunction
   209     // to be called is retrieved everytime and applied.
   210     static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
   211         final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
   212         final Object       func      = container.getSpill(slot);
   214         if (func instanceof ScriptFunction) {
   215             try {
   216                 return getINVOKE_UA_GETTER().invokeExact(func, self);
   217             } catch(final Error|RuntimeException t) {
   218                 throw t;
   219             } catch(final Throwable t) {
   220                 throw new RuntimeException(t);
   221             }
   222         }
   224         return UNDEFINED;
   225     }
   227     static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) {
   228         final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
   229         final Object       func      = container.getSpill(slot);
   231         if (func instanceof ScriptFunction) {
   232             try {
   233                 getINVOKE_UA_SETTER().invokeExact(func, self, value);
   234             } catch(final Error|RuntimeException t) {
   235                 throw t;
   236             } catch(final Throwable t) {
   237                 throw new RuntimeException(t);
   238             }
   239         }  else if (name != null) {
   240             throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
   241         }
   242     }
   244 }

mercurial