src/jdk/nashorn/internal/objects/NativeJSAdapter.java

Fri, 19 Apr 2013 18:23:00 +0530

author
sundar
date
Fri, 19 Apr 2013 18:23:00 +0530
changeset 210
c8460f668d0c
parent 133
5759f600fcf7
child 242
b754fb89367d
permissions
-rw-r--r--

8012593: JSAdapter overrides impacts strongly construction time
Reviewed-by: jlaskey, attila

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.objects;
jlaskey@3 27
jlaskey@3 28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
jlaskey@3 29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
sundar@133 30 import static jdk.nashorn.internal.lookup.Lookup.MH;
jlaskey@3 31
jlaskey@3 32 import java.lang.invoke.MethodHandle;
jlaskey@3 33 import java.lang.invoke.MethodHandles;
jlaskey@3 34 import java.lang.invoke.MethodType;
jlaskey@3 35 import java.util.ArrayList;
jlaskey@3 36 import java.util.Iterator;
jlaskey@3 37 import java.util.List;
attila@90 38 import jdk.internal.dynalink.CallSiteDescriptor;
attila@90 39 import jdk.internal.dynalink.linker.GuardedInvocation;
attila@90 40 import jdk.internal.dynalink.linker.LinkRequest;
jlaskey@3 41 import jdk.nashorn.internal.objects.annotations.Constructor;
jlaskey@3 42 import jdk.nashorn.internal.objects.annotations.ScriptClass;
jlaskey@3 43 import jdk.nashorn.internal.runtime.FindProperty;
jlaskey@3 44 import jdk.nashorn.internal.runtime.JSType;
jlaskey@3 45 import jdk.nashorn.internal.runtime.ScriptFunction;
jlaskey@3 46 import jdk.nashorn.internal.runtime.ScriptObject;
jlaskey@3 47 import jdk.nashorn.internal.runtime.ScriptRuntime;
jlaskey@3 48 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
sundar@133 49 import jdk.nashorn.internal.lookup.Lookup;
sundar@133 50 import jdk.nashorn.internal.lookup.MethodHandleFactory;
jlaskey@3 51
jlaskey@3 52 /**
jlaskey@3 53 * This class is the implementation of the Nashorn-specific global object named {@code JSAdapter}. It can be
jlaskey@3 54 * thought of as the {@link java.lang.reflect.Proxy} equivalent for JavaScript. NativeJSAdapter calls specially named
jlaskey@3 55 * JavaScript methods on an adaptee object when property access/update/call/new/delete is attempted on it. Example:
jlaskey@3 56 *<pre>
jlaskey@3 57 * var y = {
jlaskey@3 58 * __get__ : function (name) { ... }
jlaskey@3 59 * __has__ : function (name) { ... }
jlaskey@3 60 * __put__ : function (name, value) {...}
jlaskey@3 61 * __call__ : function (name, arg1, arg2) {...}
jlaskey@3 62 * __new__ : function (arg1, arg2) {...}
jlaskey@3 63 * __delete__ : function (name) { ... }
jlaskey@3 64 * __getIds__ : function () { ... }
jlaskey@3 65 * };
jlaskey@3 66 *
jlaskey@3 67 * var x = new JSAdapter(y);
jlaskey@3 68 *
jlaskey@3 69 * x.i; // calls y.__get__
jlaskey@3 70 * x.foo(); // calls y.__call__
jlaskey@3 71 * new x(); // calls y.__new__
jlaskey@3 72 * i in x; // calls y.__has__
jlaskey@3 73 * x.p = 10; // calls y.__put__
jlaskey@3 74 * delete x.p; // calls y.__delete__
jlaskey@3 75 * for (i in x) { print(i); } // calls y.__getIds__
jlaskey@3 76 * </pre>
sundar@128 77 * <p>
jlaskey@3 78 * JavaScript caller of adapter object is isolated from the fact that the property access/mutation/deletion are really
jlaskey@3 79 * calls to JavaScript methods on adaptee.
sundar@128 80 * </p>
sundar@128 81 * <p>
jlaskey@3 82 * JSAdapter constructor can optionally receive an "overrides" object. Properties of overrides object is copied to
jlaskey@3 83 * JSAdapter instance. When user accessed property is one of these, then adaptee's methods like {@code __get__},
jlaskey@3 84 * {@code __put__} etc. are not called for those. This can be used to make certain "preferred" properties that can be
jlaskey@3 85 * accessed in the usual/faster way avoiding proxy mechanism. Example:
sundar@128 86 * </p>
jlaskey@3 87 * <pre>
jlaskey@3 88 * var x = new JSAdapter({ foo: 444, bar: 6546 }) {
jlaskey@3 89 * __get__: function(name) { return name; }
jlaskey@3 90 * };
jlaskey@3 91 *
jlaskey@3 92 * x.foo; // 444 directly retrieved without __get__ call
jlaskey@3 93 * x.bar = 'hello'; // "bar" directly set without __put__ call
jlaskey@3 94 * x.prop // calls __get__("prop") as 'prop' is not overridden
jlaskey@3 95 * </pre>
jlaskey@3 96 * It is possible to pass a specific prototype for JSAdapter instance by passing three arguments to JSAdapter
jlaskey@3 97 * constructor. So exact signature of JSAdapter constructor is as follows:
jlaskey@3 98 * <pre>
jlaskey@3 99 * JSAdapter([proto], [overrides], adaptee);
jlaskey@3 100 * </pre>
jlaskey@3 101 * Both proto and overrides are optional - but adaptee is not. When proto is not passed {@code JSAdapter.prototype} is
jlaskey@3 102 * used.
jlaskey@3 103 */
jlaskey@3 104 @ScriptClass("JSAdapter")
jlaskey@3 105 public final class NativeJSAdapter extends ScriptObject {
jlaskey@3 106 /** object get operation */
jlaskey@3 107 public static final String __get__ = "__get__";
jlaskey@3 108 /** object out operation */
jlaskey@3 109 public static final String __put__ = "__put__";
jlaskey@3 110 /** object call operation */
jlaskey@3 111 public static final String __call__ = "__call__";
jlaskey@3 112 /** object new operation */
jlaskey@3 113 public static final String __new__ = "__new__";
jlaskey@3 114 /** object getIds operation */
jlaskey@3 115 public static final String __getIds__ = "__getIds__";
jlaskey@3 116 /** object getKeys operation */
jlaskey@3 117 public static final String __getKeys__ = "__getKeys__";
jlaskey@3 118 /** object getValues operation */
jlaskey@3 119 public static final String __getValues__ = "__getValues__";
jlaskey@3 120 /** object has operation */
jlaskey@3 121 public static final String __has__ = "__has__";
jlaskey@3 122 /** object delete operation */
jlaskey@3 123 public static final String __delete__ = "__delete__";
jlaskey@3 124
jlaskey@3 125 // the new extensibility, sealing and freezing operations
jlaskey@3 126
jlaskey@3 127 /** prevent extensions operation */
jlaskey@3 128 public static final String __preventExtensions__ = "__preventExtensions__";
jlaskey@3 129 /** isExtensible extensions operation */
jlaskey@3 130 public static final String __isExtensible__ = "__isExtensible__";
jlaskey@3 131 /** seal operation */
jlaskey@3 132 public static final String __seal__ = "__seal__";
jlaskey@3 133 /** isSealed extensions operation */
jlaskey@3 134 public static final String __isSealed__ = "__isSealed__";
jlaskey@3 135 /** freeze operation */
jlaskey@3 136 public static final String __freeze__ = "__freeze__";
jlaskey@3 137 /** isFrozen extensions operation */
jlaskey@3 138 public static final String __isFrozen__ = "__isFrozen__";
jlaskey@3 139
jlaskey@3 140 private final ScriptObject adaptee;
jlaskey@3 141 private final boolean overrides;
jlaskey@3 142
jlaskey@3 143 private static final MethodHandle IS_JSADAPTOR = findOwnMH("isJSAdaptor", boolean.class, Object.class, Object.class, MethodHandle.class, Object.class, ScriptFunction.class);
jlaskey@3 144
jlaskey@3 145 NativeJSAdapter(final ScriptObject proto, final Object overrides, final ScriptObject adaptee) {
jlaskey@3 146 this.adaptee = wrapAdaptee(adaptee);
jlaskey@3 147 this.setProto(proto);
jlaskey@3 148 if (overrides instanceof ScriptObject) {
jlaskey@3 149 this.overrides = true;
jlaskey@3 150 final ScriptObject sobj = (ScriptObject)overrides;
sundar@210 151 this.addBoundProperties(sobj);
jlaskey@3 152 } else {
jlaskey@3 153 this.overrides = false;
jlaskey@3 154 }
jlaskey@3 155 }
jlaskey@3 156
jlaskey@3 157 private static ScriptObject wrapAdaptee(final ScriptObject adaptee) {
jlaskey@131 158 final ScriptObject sobj = new jdk.nashorn.internal.scripts.JO();
jlaskey@3 159 sobj.setProto(adaptee);
jlaskey@3 160 return sobj;
jlaskey@3 161 }
jlaskey@3 162
jlaskey@3 163 @Override
jlaskey@3 164 public String getClassName() {
jlaskey@3 165 return "JSAdapter";
jlaskey@3 166 }
jlaskey@3 167
jlaskey@3 168 @Override
jlaskey@3 169 public int getInt(final Object key) {
jlaskey@3 170 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key);
jlaskey@3 171 }
jlaskey@3 172
jlaskey@3 173 @Override
jlaskey@3 174 public int getInt(final double key) {
jlaskey@3 175 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key);
jlaskey@3 176 }
jlaskey@3 177
jlaskey@3 178 @Override
jlaskey@3 179 public int getInt(final long key) {
jlaskey@3 180 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key);
jlaskey@3 181 }
jlaskey@3 182
jlaskey@3 183 @Override
jlaskey@3 184 public int getInt(final int key) {
jlaskey@3 185 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key);
jlaskey@3 186 }
jlaskey@3 187
jlaskey@3 188 @Override
jlaskey@3 189 public long getLong(final Object key) {
jlaskey@3 190 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key);
jlaskey@3 191 }
jlaskey@3 192
jlaskey@3 193 @Override
jlaskey@3 194 public long getLong(final double key) {
jlaskey@3 195 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key);
jlaskey@3 196 }
jlaskey@3 197
jlaskey@3 198 @Override
jlaskey@3 199 public long getLong(final long key) {
jlaskey@3 200 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key);
jlaskey@3 201 }
jlaskey@3 202
jlaskey@3 203 @Override
jlaskey@3 204 public long getLong(final int key) {
jlaskey@3 205 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key);
jlaskey@3 206 }
jlaskey@3 207
jlaskey@3 208 @Override
jlaskey@3 209 public double getDouble(final Object key) {
jlaskey@3 210 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key);
jlaskey@3 211 }
jlaskey@3 212
jlaskey@3 213 @Override
jlaskey@3 214 public double getDouble(final double key) {
jlaskey@3 215 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key);
jlaskey@3 216 }
jlaskey@3 217
jlaskey@3 218 @Override
jlaskey@3 219 public double getDouble(final long key) {
jlaskey@3 220 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key);
jlaskey@3 221 }
jlaskey@3 222
jlaskey@3 223 @Override
jlaskey@3 224 public double getDouble(final int key) {
jlaskey@3 225 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key);
jlaskey@3 226 }
jlaskey@3 227
jlaskey@3 228 @Override
jlaskey@3 229 public Object get(final Object key) {
jlaskey@3 230 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
jlaskey@3 231 }
jlaskey@3 232
jlaskey@3 233 @Override
jlaskey@3 234 public Object get(final double key) {
jlaskey@3 235 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
jlaskey@3 236 }
jlaskey@3 237
jlaskey@3 238 @Override
jlaskey@3 239 public Object get(final long key) {
jlaskey@3 240 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
jlaskey@3 241 }
jlaskey@3 242
jlaskey@3 243 @Override
jlaskey@3 244 public Object get(final int key) {
jlaskey@3 245 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
jlaskey@3 246 }
jlaskey@3 247
jlaskey@3 248 @Override
jlaskey@3 249 public void set(final Object key, final int value, final boolean strict) {
jlaskey@3 250 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 251 super.set(key, value, strict);
jlaskey@3 252 } else {
jlaskey@3 253 callAdaptee(__put__, key, value, strict);
jlaskey@3 254 }
jlaskey@3 255 }
jlaskey@3 256
jlaskey@3 257 @Override
jlaskey@3 258 public void set(final Object key, final long value, final boolean strict) {
jlaskey@3 259 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 260 super.set(key, value, strict);
jlaskey@3 261 } else {
jlaskey@3 262 callAdaptee(__put__, key, value, strict);
jlaskey@3 263 }
jlaskey@3 264 }
jlaskey@3 265
jlaskey@3 266 @Override
jlaskey@3 267 public void set(final Object key, final double value, final boolean strict) {
jlaskey@3 268 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 269 super.set(key, value, strict);
jlaskey@3 270 } else {
jlaskey@3 271 callAdaptee(__put__, key, value, strict);
jlaskey@3 272 }
jlaskey@3 273 }
jlaskey@3 274
jlaskey@3 275 @Override
jlaskey@3 276 public void set(final Object key, final Object value, final boolean strict) {
jlaskey@3 277 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 278 super.set(key, value, strict);
jlaskey@3 279 } else {
jlaskey@3 280 callAdaptee(__put__, key, value, strict);
jlaskey@3 281 }
jlaskey@3 282 }
jlaskey@3 283
jlaskey@3 284 @Override
jlaskey@3 285 public void set(final double key, final int value, final boolean strict) {
jlaskey@3 286 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 287 super.set(key, value, strict);
jlaskey@3 288 } else {
jlaskey@3 289 callAdaptee(__put__, key, value, strict);
jlaskey@3 290 }
jlaskey@3 291 }
jlaskey@3 292
jlaskey@3 293 @Override
jlaskey@3 294 public void set(final double key, final long value, final boolean strict) {
jlaskey@3 295 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 296 super.set(key, value, strict);
jlaskey@3 297 } else {
jlaskey@3 298 callAdaptee(__put__, key, value, strict);
jlaskey@3 299 }
jlaskey@3 300 }
jlaskey@3 301
jlaskey@3 302 @Override
jlaskey@3 303 public void set(final double key, final double value, final boolean strict) {
jlaskey@3 304 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 305 super.set(key, value, strict);
jlaskey@3 306 } else {
jlaskey@3 307 callAdaptee(__put__, key, value, strict);
jlaskey@3 308 }
jlaskey@3 309 }
jlaskey@3 310
jlaskey@3 311 @Override
jlaskey@3 312 public void set(final double key, final Object value, final boolean strict) {
jlaskey@3 313 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 314 super.set(key, value, strict);
jlaskey@3 315 } else {
jlaskey@3 316 callAdaptee(__put__, key, value, strict);
jlaskey@3 317 }
jlaskey@3 318 }
jlaskey@3 319
jlaskey@3 320 @Override
jlaskey@3 321 public void set(final long key, final int value, final boolean strict) {
jlaskey@3 322 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 323 super.set(key, value, strict);
jlaskey@3 324 } else {
jlaskey@3 325 callAdaptee(__put__, key, value, strict);
jlaskey@3 326 }
jlaskey@3 327 }
jlaskey@3 328
jlaskey@3 329 @Override
jlaskey@3 330 public void set(final long key, final long value, final boolean strict) {
jlaskey@3 331 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 332 super.set(key, value, strict);
jlaskey@3 333 } else {
jlaskey@3 334 callAdaptee(__put__, key, value, strict);
jlaskey@3 335 }
jlaskey@3 336 }
jlaskey@3 337
jlaskey@3 338 @Override
jlaskey@3 339 public void set(final long key, final double value, final boolean strict) {
jlaskey@3 340 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 341 super.set(key, value, strict);
jlaskey@3 342 } else {
jlaskey@3 343 callAdaptee(__put__, key, value, strict);
jlaskey@3 344 }
jlaskey@3 345 }
jlaskey@3 346
jlaskey@3 347 @Override
jlaskey@3 348 public void set(final long key, final Object value, final boolean strict) {
jlaskey@3 349 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 350 super.set(key, value, strict);
jlaskey@3 351 } else {
jlaskey@3 352 callAdaptee(__put__, key, value, strict);
jlaskey@3 353 }
jlaskey@3 354 }
jlaskey@3 355
jlaskey@3 356 @Override
jlaskey@3 357 public void set(final int key, final int value, final boolean strict) {
jlaskey@3 358 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 359 super.set(key, value, strict);
jlaskey@3 360 } else {
jlaskey@3 361 callAdaptee(__put__, key, value, strict);
jlaskey@3 362 }
jlaskey@3 363 }
jlaskey@3 364
jlaskey@3 365 @Override
jlaskey@3 366 public void set(final int key, final long value, final boolean strict) {
jlaskey@3 367 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 368 super.set(key, value, strict);
jlaskey@3 369 } else {
jlaskey@3 370 callAdaptee(__put__, key, value, strict);
jlaskey@3 371 }
jlaskey@3 372 }
jlaskey@3 373
jlaskey@3 374 @Override
jlaskey@3 375 public void set(final int key, final double value, final boolean strict) {
jlaskey@3 376 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 377 super.set(key, value, strict);
jlaskey@3 378 } else {
jlaskey@3 379 callAdaptee(__put__, key, value, strict);
jlaskey@3 380 }
jlaskey@3 381 }
jlaskey@3 382
jlaskey@3 383 @Override
jlaskey@3 384 public void set(final int key, final Object value, final boolean strict) {
jlaskey@3 385 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 386 super.set(key, value, strict);
jlaskey@3 387 } else {
jlaskey@3 388 callAdaptee(__put__, key, value, strict);
jlaskey@3 389 }
jlaskey@3 390 }
jlaskey@3 391
jlaskey@3 392 @Override
jlaskey@3 393 public boolean has(final Object key) {
jlaskey@3 394 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 395 return true;
jlaskey@3 396 }
jlaskey@3 397
jlaskey@3 398 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
jlaskey@3 399 }
jlaskey@3 400
jlaskey@3 401 @Override
jlaskey@3 402 public boolean has(final int key) {
jlaskey@3 403 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 404 return true;
jlaskey@3 405 }
jlaskey@3 406
jlaskey@3 407 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
jlaskey@3 408 }
jlaskey@3 409
jlaskey@3 410 @Override
jlaskey@3 411 public boolean has(final long key) {
jlaskey@3 412 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 413 return true;
jlaskey@3 414 }
jlaskey@3 415
jlaskey@3 416 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
jlaskey@3 417 }
jlaskey@3 418
jlaskey@3 419 @Override
jlaskey@3 420 public boolean has(final double key) {
jlaskey@3 421 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 422 return true;
jlaskey@3 423 }
jlaskey@3 424
jlaskey@3 425 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
jlaskey@3 426 }
jlaskey@3 427
jlaskey@3 428 @Override
jlaskey@3 429 public boolean delete(final int key, final boolean strict) {
jlaskey@3 430 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 431 return super.delete(key, strict);
jlaskey@3 432 }
jlaskey@3 433
jlaskey@3 434 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
jlaskey@3 435 }
jlaskey@3 436
jlaskey@3 437 @Override
jlaskey@3 438 public boolean delete(final long key, final boolean strict) {
jlaskey@3 439 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 440 return super.delete(key, strict);
jlaskey@3 441 }
jlaskey@3 442
jlaskey@3 443 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
jlaskey@3 444 }
jlaskey@3 445
jlaskey@3 446 @Override
jlaskey@3 447 public boolean delete(final double key, final boolean strict) {
jlaskey@3 448 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 449 return super.delete(key, strict);
jlaskey@3 450 }
jlaskey@3 451
jlaskey@3 452 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
jlaskey@3 453 }
jlaskey@3 454
jlaskey@3 455 @Override
jlaskey@3 456 public boolean delete(final Object key, final boolean strict) {
jlaskey@3 457 if (overrides && super.hasOwnProperty(key)) {
jlaskey@3 458 return super.delete(key, strict);
jlaskey@3 459 }
jlaskey@3 460
jlaskey@3 461 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
jlaskey@3 462 }
jlaskey@3 463
jlaskey@3 464 @Override
jlaskey@3 465 public Iterator<String> propertyIterator() {
jlaskey@3 466 // Try __getIds__ first, if not found then try __getKeys__
jlaskey@3 467 // In jdk6, we had added "__getIds__" so this is just for compatibility.
jlaskey@3 468 Object func = adaptee.get(__getIds__);
jlaskey@3 469 if (!(func instanceof ScriptFunction)) {
jlaskey@3 470 func = adaptee.get(__getKeys__);
jlaskey@3 471 }
jlaskey@3 472
jlaskey@3 473 Object obj;
jlaskey@3 474 if (func instanceof ScriptFunction) {
jlaskey@3 475 obj = ScriptRuntime.apply((ScriptFunction)func, adaptee);
jlaskey@3 476 } else {
jlaskey@3 477 obj = new NativeArray(0);
jlaskey@3 478 }
jlaskey@3 479
jlaskey@3 480 final List<String> array = new ArrayList<>();
jlaskey@3 481 for (final Iterator<Object> iter = ArrayLikeIterator.arrayLikeIterator(obj); iter.hasNext(); ) {
jlaskey@3 482 array.add((String)iter.next());
jlaskey@3 483 }
jlaskey@3 484
jlaskey@3 485 return array.iterator();
jlaskey@3 486 }
jlaskey@3 487
jlaskey@3 488
jlaskey@3 489 @Override
jlaskey@3 490 public Iterator<Object> valueIterator() {
jlaskey@3 491 final Object obj = callAdaptee(new NativeArray(0), __getValues__);
jlaskey@3 492 return ArrayLikeIterator.arrayLikeIterator(obj);
jlaskey@3 493 }
jlaskey@3 494
jlaskey@3 495 @Override
jlaskey@3 496 public ScriptObject preventExtensions() {
jlaskey@3 497 callAdaptee(__preventExtensions__);
jlaskey@3 498 return this;
jlaskey@3 499 }
jlaskey@3 500
jlaskey@3 501 @Override
jlaskey@3 502 public boolean isExtensible() {
jlaskey@3 503 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __isExtensible__));
jlaskey@3 504 }
jlaskey@3 505
jlaskey@3 506 @Override
jlaskey@3 507 public ScriptObject seal() {
jlaskey@3 508 callAdaptee(__seal__);
jlaskey@3 509 return this;
jlaskey@3 510 }
jlaskey@3 511
jlaskey@3 512 @Override
jlaskey@3 513 public boolean isSealed() {
jlaskey@3 514 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isSealed__));
jlaskey@3 515 }
jlaskey@3 516
jlaskey@3 517 @Override
jlaskey@3 518 public ScriptObject freeze() {
jlaskey@3 519 callAdaptee(__freeze__);
jlaskey@3 520 return this;
jlaskey@3 521 }
jlaskey@3 522
jlaskey@3 523 @Override
jlaskey@3 524 public boolean isFrozen() {
jlaskey@3 525 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isFrozen__));
jlaskey@3 526 }
jlaskey@3 527
jlaskey@3 528 /**
jlaskey@3 529 * Constructor
jlaskey@3 530 *
jlaskey@3 531 * @param isNew is this NativeJSAdapter instantiated with the new operator
jlaskey@3 532 * @param self self reference
jlaskey@3 533 * @param args arguments ([adaptee], [overrides, adaptee] or [proto, overrides, adaptee]
jlaskey@3 534 * @return new NativeJSAdapter
jlaskey@3 535 */
jlaskey@3 536 @Constructor
jlaskey@3 537 public static Object construct(final boolean isNew, final Object self, final Object... args) {
jlaskey@3 538 Object proto = UNDEFINED;
jlaskey@3 539 Object overrides = UNDEFINED;
jlaskey@3 540 Object adaptee;
jlaskey@3 541
jlaskey@3 542 if (args == null || args.length == 0) {
lagergren@112 543 throw typeError("not.an.object", "null");
jlaskey@3 544 }
jlaskey@3 545
jlaskey@3 546 switch (args.length) {
jlaskey@3 547 case 1:
jlaskey@3 548 adaptee = args[0];
jlaskey@3 549 break;
jlaskey@3 550
jlaskey@3 551 case 2:
jlaskey@3 552 overrides = args[0];
jlaskey@3 553 adaptee = args[1];
jlaskey@3 554 break;
jlaskey@3 555
jlaskey@3 556 default:
jlaskey@3 557 //fallthru
jlaskey@3 558 case 3:
jlaskey@3 559 proto = args[0];
jlaskey@3 560 overrides = args[1];
jlaskey@3 561 adaptee = args[2];
jlaskey@3 562 break;
jlaskey@3 563 }
jlaskey@3 564
jlaskey@3 565 if (!(adaptee instanceof ScriptObject)) {
lagergren@112 566 throw typeError("not.an.object", ScriptRuntime.safeToString(adaptee));
jlaskey@3 567 }
jlaskey@3 568
jlaskey@3 569 if (proto != null && !(proto instanceof ScriptObject)) {
jlaskey@3 570 proto = Global.instance().getJSAdapterPrototype();
jlaskey@3 571 }
jlaskey@3 572
jlaskey@3 573 return new NativeJSAdapter((ScriptObject)proto, overrides, (ScriptObject)adaptee);
jlaskey@3 574 }
jlaskey@3 575
jlaskey@3 576 @Override
jlaskey@3 577 protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
jlaskey@3 578 return findHook(desc, __new__, false);
jlaskey@3 579 }
jlaskey@3 580
jlaskey@3 581 @Override
hannesw@51 582 protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
jlaskey@3 583 if (overrides && super.hasOwnProperty(desc.getNameToken(2))) {
jlaskey@3 584 try {
hannesw@51 585 final GuardedInvocation inv = super.findCallMethodMethod(desc, request);
jlaskey@3 586 if (inv != null) {
jlaskey@3 587 return inv;
jlaskey@3 588 }
jlaskey@3 589 } catch (final Exception e) {
jlaskey@3 590 //ignored
jlaskey@3 591 }
jlaskey@3 592 }
jlaskey@3 593
jlaskey@3 594 return findHook(desc, __call__);
jlaskey@3 595 }
jlaskey@3 596
jlaskey@3 597 @Override
hannesw@51 598 protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operation) {
jlaskey@3 599 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
jlaskey@3 600 if (overrides && super.hasOwnProperty(name)) {
jlaskey@3 601 try {
hannesw@51 602 final GuardedInvocation inv = super.findGetMethod(desc, request, operation);
jlaskey@3 603 if (inv != null) {
jlaskey@3 604 return inv;
jlaskey@3 605 }
jlaskey@3 606 } catch (final Exception e) {
jlaskey@3 607 //ignored
jlaskey@3 608 }
jlaskey@3 609 }
jlaskey@3 610
jlaskey@3 611 switch(operation) {
jlaskey@3 612 case "getProp":
jlaskey@3 613 case "getElem":
jlaskey@3 614 return findHook(desc, __get__);
jlaskey@3 615 case "getMethod":
jlaskey@3 616 final FindProperty find = adaptee.findProperty(__call__, true);
jlaskey@3 617 if (find != null) {
sundar@82 618 final ScriptFunctionImpl func = (ScriptFunctionImpl)getObjectValue(find);
jlaskey@3 619 // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
jlaskey@3 620 // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
jlaskey@3 621 return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
jlaskey@3 622 func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
jlaskey@3 623 adaptee.getMap().getProtoGetSwitchPoint(__call__), testJSAdaptor(adaptee, null, null, null));
jlaskey@3 624 }
lagergren@112 625 throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
jlaskey@3 626 default:
jlaskey@3 627 break;
jlaskey@3 628 }
jlaskey@3 629
jlaskey@3 630 throw new AssertionError("should not reach here");
jlaskey@3 631 }
jlaskey@3 632
jlaskey@3 633 @Override
hannesw@51 634 protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
jlaskey@3 635 if (overrides && super.hasOwnProperty(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
jlaskey@3 636 try {
hannesw@51 637 final GuardedInvocation inv = super.findSetMethod(desc, request);
jlaskey@3 638 if (inv != null) {
jlaskey@3 639 return inv;
jlaskey@3 640 }
jlaskey@3 641 } catch (final Exception e) {
jlaskey@3 642 //ignored
jlaskey@3 643 }
jlaskey@3 644 }
jlaskey@3 645
jlaskey@3 646 return findHook(desc, __put__);
jlaskey@3 647 }
jlaskey@3 648
jlaskey@3 649 // -- Internals only below this point
jlaskey@3 650 private Object callAdaptee(final String name, final Object... args) {
jlaskey@3 651 return callAdaptee(UNDEFINED, name, args);
jlaskey@3 652 }
jlaskey@3 653
jlaskey@3 654 private double callAdapteeDouble(final String name, final Object... args) {
jlaskey@3 655 return JSType.toNumber(callAdaptee(name, args));
jlaskey@3 656 }
jlaskey@3 657
jlaskey@3 658 private long callAdapteeLong(final String name, final Object... args) {
jlaskey@3 659 return JSType.toLong(callAdaptee(name, args));
jlaskey@3 660 }
jlaskey@3 661
jlaskey@3 662 private int callAdapteeInt(final String name, final Object... args) {
jlaskey@3 663 return JSType.toInt32(callAdaptee(name, args));
jlaskey@3 664 }
jlaskey@3 665
jlaskey@3 666 private Object callAdaptee(final Object retValue, final String name, final Object... args) {
jlaskey@3 667 final Object func = adaptee.get(name);
jlaskey@3 668 if (func instanceof ScriptFunction) {
jlaskey@3 669 return ScriptRuntime.apply((ScriptFunction)func, adaptee, args);
jlaskey@3 670 }
jlaskey@3 671 return retValue;
jlaskey@3 672 }
jlaskey@3 673
jlaskey@3 674 private GuardedInvocation findHook(final CallSiteDescriptor desc, final String hook) {
jlaskey@3 675 return findHook(desc, hook, true);
jlaskey@3 676 }
jlaskey@3 677
jlaskey@3 678 private GuardedInvocation findHook(final CallSiteDescriptor desc, final String hook, final boolean useName) {
jlaskey@3 679 final FindProperty findData = adaptee.findProperty(hook, true);
jlaskey@3 680 final MethodType type = desc.getMethodType();
jlaskey@3 681 if (findData != null) {
jlaskey@3 682 final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
jlaskey@3 683 final ScriptFunction func = (ScriptFunction)getObjectValue(findData);
jlaskey@3 684
jlaskey@3 685 final MethodHandle methodHandle = getCallMethodHandle(findData, type,
jlaskey@3 686 useName ? name : null);
jlaskey@3 687 if (methodHandle != null) {
jlaskey@3 688 return new GuardedInvocation(
jlaskey@3 689 methodHandle,
jlaskey@3 690 adaptee.getMap().getProtoGetSwitchPoint(hook),
jlaskey@3 691 testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
jlaskey@3 692 }
jlaskey@3 693 }
jlaskey@3 694
jlaskey@3 695 switch (hook) {
jlaskey@3 696 case __call__:
lagergren@112 697 throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
jlaskey@3 698 default:
jlaskey@3 699 final MethodHandle methodHandle = hook.equals(__put__) ?
jlaskey@3 700 MH.asType(Lookup.EMPTY_SETTER, type) :
jlaskey@3 701 Lookup.emptyGetter(type.returnType());
jlaskey@3 702 return new GuardedInvocation(methodHandle, adaptee.getMap().getProtoGetSwitchPoint(hook), testJSAdaptor(adaptee, null, null, null));
jlaskey@3 703 }
jlaskey@3 704 }
jlaskey@3 705
jlaskey@3 706 private static MethodHandle testJSAdaptor(final Object adaptee, final MethodHandle getter, final Object where, final ScriptFunction func) {
jlaskey@3 707 return MH.insertArguments(IS_JSADAPTOR, 1, adaptee, getter, where, func);
jlaskey@3 708 }
jlaskey@3 709
jlaskey@3 710 @SuppressWarnings("unused")
jlaskey@3 711 private static boolean isJSAdaptor(final Object self, final Object adaptee, final MethodHandle getter, final Object where, final ScriptFunction func) {
jlaskey@3 712 final boolean res = self instanceof NativeJSAdapter && ((NativeJSAdapter)self).getAdaptee() == adaptee;
jlaskey@3 713 if (res && getter != null) {
jlaskey@3 714 try {
jlaskey@3 715 return getter.invokeExact(where) == func;
jlaskey@3 716 } catch (final RuntimeException | Error e) {
jlaskey@3 717 throw e;
jlaskey@3 718 } catch (final Throwable t) {
jlaskey@3 719 throw new RuntimeException(t);
jlaskey@3 720 }
jlaskey@3 721 }
jlaskey@3 722
jlaskey@3 723 return res;
jlaskey@3 724 }
jlaskey@3 725
jlaskey@3 726 /**
jlaskey@3 727 * Get the adaptee
jlaskey@3 728 * @return adaptee ScriptObject
jlaskey@3 729 */
jlaskey@3 730 public ScriptObject getAdaptee() {
jlaskey@3 731 return adaptee;
jlaskey@3 732 }
jlaskey@3 733
jlaskey@3 734 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
sundar@36 735 try {
sundar@36 736 return MethodHandles.lookup().findStatic(NativeJSAdapter.class, name, MH.type(rtype, types));
sundar@36 737 } catch (final NoSuchMethodException | IllegalAccessException e) {
sundar@37 738 throw new MethodHandleFactory.LookupException(e);
sundar@36 739 }
jlaskey@3 740 }
jlaskey@3 741 }

mercurial