src/jdk/nashorn/api/scripting/ScriptObjectMirror.java

Thu, 12 Oct 2017 19:52:15 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:52:15 +0800
changeset 1205
4112748288bb
parent 1020
9ee8fd4a7266
parent 952
6d5471a497fb
child 1490
d85f981c8cf8
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package jdk.nashorn.api.scripting;
aoqi@0 27
aoqi@0 28 import java.nio.ByteBuffer;
aoqi@0 29 import java.security.AccessControlContext;
aoqi@0 30 import java.security.AccessController;
aoqi@0 31 import java.security.Permissions;
aoqi@0 32 import java.security.PrivilegedAction;
aoqi@0 33 import java.security.ProtectionDomain;
aoqi@0 34 import java.util.AbstractMap;
aoqi@0 35 import java.util.ArrayList;
aoqi@0 36 import java.util.Collection;
aoqi@0 37 import java.util.Collections;
aoqi@0 38 import java.util.Iterator;
aoqi@0 39 import java.util.LinkedHashSet;
aoqi@0 40 import java.util.List;
aoqi@0 41 import java.util.Map;
aoqi@0 42 import java.util.Set;
aoqi@0 43 import java.util.concurrent.Callable;
aoqi@0 44 import javax.script.Bindings;
aoqi@0 45 import jdk.nashorn.internal.objects.Global;
aoqi@0 46 import jdk.nashorn.internal.runtime.ConsString;
aoqi@0 47 import jdk.nashorn.internal.runtime.Context;
aoqi@0 48 import jdk.nashorn.internal.runtime.JSType;
aoqi@0 49 import jdk.nashorn.internal.runtime.ScriptFunction;
aoqi@0 50 import jdk.nashorn.internal.runtime.ScriptObject;
aoqi@0 51 import jdk.nashorn.internal.runtime.ScriptRuntime;
attila@962 52 import jdk.nashorn.internal.runtime.arrays.ArrayData;
hannesw@1020 53 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
aoqi@0 54
aoqi@0 55 /**
aoqi@0 56 * Mirror object that wraps a given Nashorn Script object.
aoqi@0 57 */
aoqi@0 58 public final class ScriptObjectMirror extends AbstractJSObject implements Bindings {
aoqi@0 59 private static AccessControlContext getContextAccCtxt() {
aoqi@0 60 final Permissions perms = new Permissions();
aoqi@0 61 perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
aoqi@0 62 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
aoqi@0 63 }
aoqi@0 64
aoqi@0 65 private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt();
aoqi@0 66
aoqi@0 67 private final ScriptObject sobj;
aoqi@0 68 private final Global global;
aoqi@0 69 private final boolean strict;
aoqi@0 70
aoqi@0 71 @Override
aoqi@0 72 public boolean equals(final Object other) {
aoqi@0 73 if (other instanceof ScriptObjectMirror) {
aoqi@0 74 return sobj.equals(((ScriptObjectMirror)other).sobj);
aoqi@0 75 }
aoqi@0 76
aoqi@0 77 return false;
aoqi@0 78 }
aoqi@0 79
aoqi@0 80 @Override
aoqi@0 81 public int hashCode() {
aoqi@0 82 return sobj.hashCode();
aoqi@0 83 }
aoqi@0 84
aoqi@0 85 @Override
aoqi@0 86 public String toString() {
aoqi@0 87 return inGlobal(new Callable<String>() {
aoqi@0 88 @Override
aoqi@0 89 public String call() {
aoqi@0 90 return ScriptRuntime.safeToString(sobj);
aoqi@0 91 }
aoqi@0 92 });
aoqi@0 93 }
aoqi@0 94
aoqi@0 95 // JSObject methods
aoqi@0 96
aoqi@0 97 @Override
aoqi@0 98 public Object call(final Object thiz, final Object... args) {
aoqi@0 99 final Global oldGlobal = Context.getGlobal();
aoqi@0 100 final boolean globalChanged = (oldGlobal != global);
aoqi@0 101
aoqi@0 102 try {
aoqi@0 103 if (globalChanged) {
aoqi@0 104 Context.setGlobal(global);
aoqi@0 105 }
aoqi@0 106
aoqi@0 107 if (sobj instanceof ScriptFunction) {
aoqi@0 108 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
aoqi@0 109 final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz;
aoqi@0 110 return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global);
aoqi@0 111 }
aoqi@0 112
aoqi@0 113 throw new RuntimeException("not a function: " + toString());
aoqi@0 114 } catch (final NashornException ne) {
aoqi@0 115 throw ne.initEcmaError(global);
aoqi@0 116 } catch (final RuntimeException | Error e) {
aoqi@0 117 throw e;
aoqi@0 118 } catch (final Throwable t) {
aoqi@0 119 throw new RuntimeException(t);
aoqi@0 120 } finally {
aoqi@0 121 if (globalChanged) {
aoqi@0 122 Context.setGlobal(oldGlobal);
aoqi@0 123 }
aoqi@0 124 }
aoqi@0 125 }
aoqi@0 126
aoqi@0 127 @Override
aoqi@0 128 public Object newObject(final Object... args) {
aoqi@0 129 final Global oldGlobal = Context.getGlobal();
aoqi@0 130 final boolean globalChanged = (oldGlobal != global);
aoqi@0 131
aoqi@0 132 try {
aoqi@0 133 if (globalChanged) {
aoqi@0 134 Context.setGlobal(global);
aoqi@0 135 }
aoqi@0 136
aoqi@0 137 if (sobj instanceof ScriptFunction) {
aoqi@0 138 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
aoqi@0 139 return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global);
aoqi@0 140 }
aoqi@0 141
aoqi@0 142 throw new RuntimeException("not a constructor: " + toString());
aoqi@0 143 } catch (final NashornException ne) {
aoqi@0 144 throw ne.initEcmaError(global);
aoqi@0 145 } catch (final RuntimeException | Error e) {
aoqi@0 146 throw e;
aoqi@0 147 } catch (final Throwable t) {
aoqi@0 148 throw new RuntimeException(t);
aoqi@0 149 } finally {
aoqi@0 150 if (globalChanged) {
aoqi@0 151 Context.setGlobal(oldGlobal);
aoqi@0 152 }
aoqi@0 153 }
aoqi@0 154 }
aoqi@0 155
aoqi@0 156 @Override
aoqi@0 157 public Object eval(final String s) {
aoqi@0 158 return inGlobal(new Callable<Object>() {
aoqi@0 159 @Override
aoqi@0 160 public Object call() {
aoqi@0 161 final Context context = AccessController.doPrivileged(
aoqi@0 162 new PrivilegedAction<Context>() {
aoqi@0 163 @Override
aoqi@0 164 public Context run() {
aoqi@0 165 return Context.getContext();
aoqi@0 166 }
aoqi@0 167 }, GET_CONTEXT_ACC_CTXT);
sundar@965 168 return wrap(context.eval(global, s, sobj, null, false), global);
aoqi@0 169 }
aoqi@0 170 });
aoqi@0 171 }
aoqi@0 172
attila@963 173 /**
attila@963 174 * Call member function
attila@963 175 * @param functionName function name
attila@963 176 * @param args arguments
attila@963 177 * @return return value of function
attila@963 178 */
aoqi@0 179 public Object callMember(final String functionName, final Object... args) {
aoqi@0 180 functionName.getClass(); // null check
aoqi@0 181 final Global oldGlobal = Context.getGlobal();
aoqi@0 182 final boolean globalChanged = (oldGlobal != global);
aoqi@0 183
aoqi@0 184 try {
aoqi@0 185 if (globalChanged) {
aoqi@0 186 Context.setGlobal(global);
aoqi@0 187 }
aoqi@0 188
aoqi@0 189 final Object val = sobj.get(functionName);
aoqi@0 190 if (val instanceof ScriptFunction) {
aoqi@0 191 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
aoqi@0 192 return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
aoqi@0 193 } else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
aoqi@0 194 return ((JSObject)val).call(sobj, args);
aoqi@0 195 }
aoqi@0 196
aoqi@0 197 throw new NoSuchMethodException("No such function " + functionName);
aoqi@0 198 } catch (final NashornException ne) {
aoqi@0 199 throw ne.initEcmaError(global);
aoqi@0 200 } catch (final RuntimeException | Error e) {
aoqi@0 201 throw e;
aoqi@0 202 } catch (final Throwable t) {
aoqi@0 203 throw new RuntimeException(t);
aoqi@0 204 } finally {
aoqi@0 205 if (globalChanged) {
aoqi@0 206 Context.setGlobal(oldGlobal);
aoqi@0 207 }
aoqi@0 208 }
aoqi@0 209 }
aoqi@0 210
aoqi@0 211 @Override
aoqi@0 212 public Object getMember(final String name) {
aoqi@0 213 name.getClass();
aoqi@0 214 return inGlobal(new Callable<Object>() {
aoqi@0 215 @Override public Object call() {
aoqi@0 216 return wrap(sobj.get(name), global);
aoqi@0 217 }
aoqi@0 218 });
aoqi@0 219 }
aoqi@0 220
aoqi@0 221 @Override
aoqi@0 222 public Object getSlot(final int index) {
aoqi@0 223 return inGlobal(new Callable<Object>() {
aoqi@0 224 @Override public Object call() {
aoqi@0 225 return wrap(sobj.get(index), global);
aoqi@0 226 }
aoqi@0 227 });
aoqi@0 228 }
aoqi@0 229
aoqi@0 230 @Override
aoqi@0 231 public boolean hasMember(final String name) {
aoqi@0 232 name.getClass();
aoqi@0 233 return inGlobal(new Callable<Boolean>() {
aoqi@0 234 @Override public Boolean call() {
aoqi@0 235 return sobj.has(name);
aoqi@0 236 }
aoqi@0 237 });
aoqi@0 238 }
aoqi@0 239
aoqi@0 240 @Override
aoqi@0 241 public boolean hasSlot(final int slot) {
aoqi@0 242 return inGlobal(new Callable<Boolean>() {
aoqi@0 243 @Override public Boolean call() {
aoqi@0 244 return sobj.has(slot);
aoqi@0 245 }
aoqi@0 246 });
aoqi@0 247 }
aoqi@0 248
aoqi@0 249 @Override
aoqi@0 250 public void removeMember(final String name) {
aoqi@0 251 name.getClass();
aoqi@0 252 remove(name);
aoqi@0 253 }
aoqi@0 254
aoqi@0 255 @Override
aoqi@0 256 public void setMember(final String name, final Object value) {
aoqi@0 257 name.getClass();
aoqi@0 258 put(name, value);
aoqi@0 259 }
aoqi@0 260
aoqi@0 261 @Override
aoqi@0 262 public void setSlot(final int index, final Object value) {
aoqi@0 263 inGlobal(new Callable<Void>() {
aoqi@0 264 @Override public Void call() {
hannesw@1020 265 sobj.set(index, unwrap(value, global), getCallSiteFlags());
aoqi@0 266 return null;
aoqi@0 267 }
aoqi@0 268 });
aoqi@0 269 }
aoqi@0 270
aoqi@0 271 /**
aoqi@0 272 * Nashorn extension: setIndexedPropertiesToExternalArrayData.
aoqi@0 273 * set indexed properties be exposed from a given nio ByteBuffer.
aoqi@0 274 *
aoqi@0 275 * @param buf external buffer - should be a nio ByteBuffer
aoqi@0 276 */
aoqi@0 277 public void setIndexedPropertiesToExternalArrayData(final ByteBuffer buf) {
aoqi@0 278 inGlobal(new Callable<Void>() {
aoqi@0 279 @Override public Void call() {
aoqi@0 280 sobj.setArray(ArrayData.allocate(buf));
aoqi@0 281 return null;
aoqi@0 282 }
aoqi@0 283 });
aoqi@0 284 }
aoqi@0 285
aoqi@0 286
aoqi@0 287 @Override
aoqi@0 288 public boolean isInstance(final Object obj) {
aoqi@0 289 if (! (obj instanceof ScriptObjectMirror)) {
aoqi@0 290 return false;
aoqi@0 291 }
aoqi@0 292
aoqi@0 293 final ScriptObjectMirror instance = (ScriptObjectMirror)obj;
aoqi@0 294 // if not belongs to my global scope, return false
aoqi@0 295 if (global != instance.global) {
aoqi@0 296 return false;
aoqi@0 297 }
aoqi@0 298
aoqi@0 299 return inGlobal(new Callable<Boolean>() {
aoqi@0 300 @Override public Boolean call() {
aoqi@0 301 return sobj.isInstance(instance.sobj);
aoqi@0 302 }
aoqi@0 303 });
aoqi@0 304 }
aoqi@0 305
aoqi@0 306 @Override
aoqi@0 307 public String getClassName() {
aoqi@0 308 return sobj.getClassName();
aoqi@0 309 }
aoqi@0 310
aoqi@0 311 @Override
aoqi@0 312 public boolean isFunction() {
aoqi@0 313 return sobj instanceof ScriptFunction;
aoqi@0 314 }
aoqi@0 315
aoqi@0 316 @Override
aoqi@0 317 public boolean isStrictFunction() {
aoqi@0 318 return isFunction() && ((ScriptFunction)sobj).isStrict();
aoqi@0 319 }
aoqi@0 320
aoqi@0 321 @Override
aoqi@0 322 public boolean isArray() {
aoqi@0 323 return sobj.isArray();
aoqi@0 324 }
aoqi@0 325
aoqi@0 326 // javax.script.Bindings methods
aoqi@0 327
aoqi@0 328 @Override
aoqi@0 329 public void clear() {
aoqi@0 330 inGlobal(new Callable<Object>() {
aoqi@0 331 @Override public Object call() {
aoqi@0 332 sobj.clear(strict);
aoqi@0 333 return null;
aoqi@0 334 }
aoqi@0 335 });
aoqi@0 336 }
aoqi@0 337
aoqi@0 338 @Override
aoqi@0 339 public boolean containsKey(final Object key) {
aoqi@0 340 return inGlobal(new Callable<Boolean>() {
aoqi@0 341 @Override public Boolean call() {
aoqi@0 342 return sobj.containsKey(unwrap(key, global));
aoqi@0 343 }
aoqi@0 344 });
aoqi@0 345 }
aoqi@0 346
aoqi@0 347 @Override
aoqi@0 348 public boolean containsValue(final Object value) {
aoqi@0 349 return inGlobal(new Callable<Boolean>() {
aoqi@0 350 @Override public Boolean call() {
aoqi@0 351 return sobj.containsValue(unwrap(value, global));
aoqi@0 352 }
aoqi@0 353 });
aoqi@0 354 }
aoqi@0 355
aoqi@0 356 @Override
aoqi@0 357 public Set<Map.Entry<String, Object>> entrySet() {
aoqi@0 358 return inGlobal(new Callable<Set<Map.Entry<String, Object>>>() {
aoqi@0 359 @Override public Set<Map.Entry<String, Object>> call() {
aoqi@0 360 final Iterator<String> iter = sobj.propertyIterator();
aoqi@0 361 final Set<Map.Entry<String, Object>> entries = new LinkedHashSet<>();
aoqi@0 362
aoqi@0 363 while (iter.hasNext()) {
aoqi@0 364 final String key = iter.next();
aoqi@0 365 final Object value = translateUndefined(wrap(sobj.get(key), global));
aoqi@0 366 entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
aoqi@0 367 }
aoqi@0 368
aoqi@0 369 return Collections.unmodifiableSet(entries);
aoqi@0 370 }
aoqi@0 371 });
aoqi@0 372 }
aoqi@0 373
aoqi@0 374 @Override
aoqi@0 375 public Object get(final Object key) {
aoqi@0 376 return inGlobal(new Callable<Object>() {
aoqi@0 377 @Override public Object call() {
aoqi@0 378 return translateUndefined(wrap(sobj.get(key), global));
aoqi@0 379 }
aoqi@0 380 });
aoqi@0 381 }
aoqi@0 382
aoqi@0 383 @Override
aoqi@0 384 public boolean isEmpty() {
aoqi@0 385 return inGlobal(new Callable<Boolean>() {
aoqi@0 386 @Override public Boolean call() {
aoqi@0 387 return sobj.isEmpty();
aoqi@0 388 }
aoqi@0 389 });
aoqi@0 390 }
aoqi@0 391
aoqi@0 392 @Override
aoqi@0 393 public Set<String> keySet() {
aoqi@0 394 return inGlobal(new Callable<Set<String>>() {
aoqi@0 395 @Override public Set<String> call() {
aoqi@0 396 final Iterator<String> iter = sobj.propertyIterator();
aoqi@0 397 final Set<String> keySet = new LinkedHashSet<>();
aoqi@0 398
aoqi@0 399 while (iter.hasNext()) {
aoqi@0 400 keySet.add(iter.next());
aoqi@0 401 }
aoqi@0 402
aoqi@0 403 return Collections.unmodifiableSet(keySet);
aoqi@0 404 }
aoqi@0 405 });
aoqi@0 406 }
aoqi@0 407
aoqi@0 408 @Override
aoqi@0 409 public Object put(final String key, final Object value) {
aoqi@0 410 final ScriptObject oldGlobal = Context.getGlobal();
aoqi@0 411 final boolean globalChanged = (oldGlobal != global);
aoqi@0 412 return inGlobal(new Callable<Object>() {
aoqi@0 413 @Override public Object call() {
aoqi@0 414 final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
aoqi@0 415 return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global));
aoqi@0 416 }
aoqi@0 417 });
aoqi@0 418 }
aoqi@0 419
aoqi@0 420 @Override
aoqi@0 421 public void putAll(final Map<? extends String, ? extends Object> map) {
aoqi@0 422 final ScriptObject oldGlobal = Context.getGlobal();
aoqi@0 423 final boolean globalChanged = (oldGlobal != global);
aoqi@0 424 inGlobal(new Callable<Object>() {
aoqi@0 425 @Override public Object call() {
aoqi@0 426 for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
aoqi@0 427 final Object value = entry.getValue();
aoqi@0 428 final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
hannesw@1020 429 sobj.set(entry.getKey(), unwrap(modValue, global), getCallSiteFlags());
aoqi@0 430 }
aoqi@0 431 return null;
aoqi@0 432 }
aoqi@0 433 });
aoqi@0 434 }
aoqi@0 435
aoqi@0 436 @Override
aoqi@0 437 public Object remove(final Object key) {
aoqi@0 438 return inGlobal(new Callable<Object>() {
aoqi@0 439 @Override public Object call() {
aoqi@0 440 return wrap(sobj.remove(unwrap(key, global), strict), global);
aoqi@0 441 }
aoqi@0 442 });
aoqi@0 443 }
aoqi@0 444
aoqi@0 445 /**
aoqi@0 446 * Delete a property from this object.
aoqi@0 447 *
aoqi@0 448 * @param key the property to be deleted
aoqi@0 449 *
aoqi@0 450 * @return if the delete was successful or not
aoqi@0 451 */
aoqi@0 452 public boolean delete(final Object key) {
aoqi@0 453 return inGlobal(new Callable<Boolean>() {
aoqi@0 454 @Override public Boolean call() {
aoqi@0 455 return sobj.delete(unwrap(key, global), strict);
aoqi@0 456 }
aoqi@0 457 });
aoqi@0 458 }
aoqi@0 459
aoqi@0 460 @Override
aoqi@0 461 public int size() {
aoqi@0 462 return inGlobal(new Callable<Integer>() {
aoqi@0 463 @Override public Integer call() {
aoqi@0 464 return sobj.size();
aoqi@0 465 }
aoqi@0 466 });
aoqi@0 467 }
aoqi@0 468
aoqi@0 469 @Override
aoqi@0 470 public Collection<Object> values() {
aoqi@0 471 return inGlobal(new Callable<Collection<Object>>() {
aoqi@0 472 @Override public Collection<Object> call() {
aoqi@0 473 final List<Object> values = new ArrayList<>(size());
aoqi@0 474 final Iterator<Object> iter = sobj.valueIterator();
aoqi@0 475
aoqi@0 476 while (iter.hasNext()) {
aoqi@0 477 values.add(translateUndefined(wrap(iter.next(), global)));
aoqi@0 478 }
aoqi@0 479
aoqi@0 480 return Collections.unmodifiableList(values);
aoqi@0 481 }
aoqi@0 482 });
aoqi@0 483 }
aoqi@0 484
aoqi@0 485 // Support for ECMAScript Object API on mirrors
aoqi@0 486
aoqi@0 487 /**
aoqi@0 488 * Return the __proto__ of this object.
aoqi@0 489 * @return __proto__ object.
aoqi@0 490 */
aoqi@0 491 public Object getProto() {
aoqi@0 492 return inGlobal(new Callable<Object>() {
aoqi@0 493 @Override public Object call() {
aoqi@0 494 return wrap(sobj.getProto(), global);
aoqi@0 495 }
aoqi@0 496 });
aoqi@0 497 }
aoqi@0 498
aoqi@0 499 /**
aoqi@0 500 * Set the __proto__ of this object.
aoqi@0 501 * @param proto new proto for this object
aoqi@0 502 */
aoqi@0 503 public void setProto(final Object proto) {
aoqi@0 504 inGlobal(new Callable<Void>() {
aoqi@0 505 @Override public Void call() {
aoqi@0 506 sobj.setPrototypeOf(unwrap(proto, global));
aoqi@0 507 return null;
aoqi@0 508 }
aoqi@0 509 });
aoqi@0 510 }
aoqi@0 511
aoqi@0 512 /**
aoqi@0 513 * ECMA 8.12.1 [[GetOwnProperty]] (P)
aoqi@0 514 *
aoqi@0 515 * @param key property key
aoqi@0 516 *
aoqi@0 517 * @return Returns the Property Descriptor of the named own property of this
aoqi@0 518 * object, or undefined if absent.
aoqi@0 519 */
aoqi@0 520 public Object getOwnPropertyDescriptor(final String key) {
aoqi@0 521 return inGlobal(new Callable<Object>() {
aoqi@0 522 @Override public Object call() {
aoqi@0 523 return wrap(sobj.getOwnPropertyDescriptor(key), global);
aoqi@0 524 }
aoqi@0 525 });
aoqi@0 526 }
aoqi@0 527
aoqi@0 528 /**
aoqi@0 529 * return an array of own property keys associated with the object.
aoqi@0 530 *
aoqi@0 531 * @param all True if to include non-enumerable keys.
aoqi@0 532 * @return Array of keys.
aoqi@0 533 */
aoqi@0 534 public String[] getOwnKeys(final boolean all) {
aoqi@0 535 return inGlobal(new Callable<String[]>() {
aoqi@0 536 @Override public String[] call() {
aoqi@0 537 return sobj.getOwnKeys(all);
aoqi@0 538 }
aoqi@0 539 });
aoqi@0 540 }
aoqi@0 541
aoqi@0 542 /**
aoqi@0 543 * Flag this script object as non extensible
aoqi@0 544 *
aoqi@0 545 * @return the object after being made non extensible
aoqi@0 546 */
aoqi@0 547 public ScriptObjectMirror preventExtensions() {
aoqi@0 548 return inGlobal(new Callable<ScriptObjectMirror>() {
aoqi@0 549 @Override public ScriptObjectMirror call() {
aoqi@0 550 sobj.preventExtensions();
aoqi@0 551 return ScriptObjectMirror.this;
aoqi@0 552 }
aoqi@0 553 });
aoqi@0 554 }
aoqi@0 555
aoqi@0 556 /**
aoqi@0 557 * Check if this script object is extensible
aoqi@0 558 * @return true if extensible
aoqi@0 559 */
aoqi@0 560 public boolean isExtensible() {
aoqi@0 561 return inGlobal(new Callable<Boolean>() {
aoqi@0 562 @Override public Boolean call() {
aoqi@0 563 return sobj.isExtensible();
aoqi@0 564 }
aoqi@0 565 });
aoqi@0 566 }
aoqi@0 567
aoqi@0 568 /**
aoqi@0 569 * ECMAScript 15.2.3.8 - seal implementation
aoqi@0 570 * @return the sealed script object
aoqi@0 571 */
aoqi@0 572 public ScriptObjectMirror seal() {
aoqi@0 573 return inGlobal(new Callable<ScriptObjectMirror>() {
aoqi@0 574 @Override public ScriptObjectMirror call() {
aoqi@0 575 sobj.seal();
aoqi@0 576 return ScriptObjectMirror.this;
aoqi@0 577 }
aoqi@0 578 });
aoqi@0 579 }
aoqi@0 580
aoqi@0 581 /**
aoqi@0 582 * Check whether this script object is sealed
aoqi@0 583 * @return true if sealed
aoqi@0 584 */
aoqi@0 585 public boolean isSealed() {
aoqi@0 586 return inGlobal(new Callable<Boolean>() {
aoqi@0 587 @Override public Boolean call() {
aoqi@0 588 return sobj.isSealed();
aoqi@0 589 }
aoqi@0 590 });
aoqi@0 591 }
aoqi@0 592
aoqi@0 593 /**
aoqi@0 594 * ECMA 15.2.39 - freeze implementation. Freeze this script object
aoqi@0 595 * @return the frozen script object
aoqi@0 596 */
aoqi@0 597 public ScriptObjectMirror freeze() {
aoqi@0 598 return inGlobal(new Callable<ScriptObjectMirror>() {
aoqi@0 599 @Override public ScriptObjectMirror call() {
aoqi@0 600 sobj.freeze();
aoqi@0 601 return ScriptObjectMirror.this;
aoqi@0 602 }
aoqi@0 603 });
aoqi@0 604 }
aoqi@0 605
aoqi@0 606 /**
aoqi@0 607 * Check whether this script object is frozen
aoqi@0 608 * @return true if frozen
aoqi@0 609 */
aoqi@0 610 public boolean isFrozen() {
aoqi@0 611 return inGlobal(new Callable<Boolean>() {
aoqi@0 612 @Override public Boolean call() {
aoqi@0 613 return sobj.isFrozen();
aoqi@0 614 }
aoqi@0 615 });
aoqi@0 616 }
aoqi@0 617
aoqi@0 618 /**
aoqi@0 619 * Utility to check if given object is ECMAScript undefined value
aoqi@0 620 *
aoqi@0 621 * @param obj object to check
aoqi@0 622 * @return true if 'obj' is ECMAScript undefined value
aoqi@0 623 */
aoqi@0 624 public static boolean isUndefined(final Object obj) {
aoqi@0 625 return obj == ScriptRuntime.UNDEFINED;
aoqi@0 626 }
aoqi@0 627
aoqi@0 628 /**
aoqi@0 629 * Utilitity to convert this script object to the given type.
aoqi@0 630 *
aoqi@0 631 * @param <T> destination type to convert to
aoqi@0 632 * @param type destination type to convert to
aoqi@0 633 * @return converted object
aoqi@0 634 */
aoqi@0 635 public <T> T to(final Class<T> type) {
aoqi@0 636 return inGlobal(new Callable<T>() {
aoqi@0 637 @Override
aoqi@0 638 public T call() {
aoqi@0 639 return type.cast(ScriptUtils.convert(sobj, type));
aoqi@0 640 }
aoqi@0 641 });
aoqi@0 642 }
aoqi@0 643
aoqi@0 644 /**
aoqi@0 645 * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
aoqi@0 646 *
aoqi@0 647 * @param obj object to be wrapped/converted
aoqi@0 648 * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
aoqi@0 649 * @return wrapped/converted object
aoqi@0 650 */
aoqi@0 651 public static Object wrap(final Object obj, final Object homeGlobal) {
aoqi@0 652 if(obj instanceof ScriptObject) {
aoqi@0 653 return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj;
aoqi@0 654 }
aoqi@0 655 if(obj instanceof ConsString) {
aoqi@0 656 return obj.toString();
aoqi@0 657 }
aoqi@0 658 return obj;
aoqi@0 659 }
aoqi@0 660
aoqi@0 661 /**
aoqi@0 662 * Unwrap a script object mirror if needed.
aoqi@0 663 *
aoqi@0 664 * @param obj object to be unwrapped
aoqi@0 665 * @param homeGlobal global to which this object belongs
aoqi@0 666 * @return unwrapped object
aoqi@0 667 */
aoqi@0 668 public static Object unwrap(final Object obj, final Object homeGlobal) {
aoqi@0 669 if (obj instanceof ScriptObjectMirror) {
aoqi@0 670 final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
aoqi@0 671 return (mirror.global == homeGlobal)? mirror.sobj : obj;
aoqi@0 672 }
aoqi@0 673
aoqi@0 674 return obj;
aoqi@0 675 }
aoqi@0 676
aoqi@0 677 /**
aoqi@0 678 * Wrap an array of object to script object mirrors if needed.
aoqi@0 679 *
aoqi@0 680 * @param args array to be unwrapped
aoqi@0 681 * @param homeGlobal global to which this object belongs
aoqi@0 682 * @return wrapped array
aoqi@0 683 */
aoqi@0 684 public static Object[] wrapArray(final Object[] args, final Object homeGlobal) {
aoqi@0 685 if (args == null || args.length == 0) {
aoqi@0 686 return args;
aoqi@0 687 }
aoqi@0 688
aoqi@0 689 final Object[] newArgs = new Object[args.length];
aoqi@0 690 int index = 0;
aoqi@0 691 for (final Object obj : args) {
aoqi@0 692 newArgs[index] = wrap(obj, homeGlobal);
aoqi@0 693 index++;
aoqi@0 694 }
aoqi@0 695 return newArgs;
aoqi@0 696 }
aoqi@0 697
aoqi@0 698 /**
aoqi@0 699 * Unwrap an array of script object mirrors if needed.
aoqi@0 700 *
aoqi@0 701 * @param args array to be unwrapped
aoqi@0 702 * @param homeGlobal global to which this object belongs
aoqi@0 703 * @return unwrapped array
aoqi@0 704 */
aoqi@0 705 public static Object[] unwrapArray(final Object[] args, final Object homeGlobal) {
aoqi@0 706 if (args == null || args.length == 0) {
aoqi@0 707 return args;
aoqi@0 708 }
aoqi@0 709
aoqi@0 710 final Object[] newArgs = new Object[args.length];
aoqi@0 711 int index = 0;
aoqi@0 712 for (final Object obj : args) {
aoqi@0 713 newArgs[index] = unwrap(obj, homeGlobal);
aoqi@0 714 index++;
aoqi@0 715 }
aoqi@0 716 return newArgs;
aoqi@0 717 }
aoqi@0 718
attila@963 719 /**
attila@963 720 * Are the given objects mirrors to same underlying object?
attila@963 721 *
attila@963 722 * @param obj1 first object
attila@963 723 * @param obj2 second object
attila@963 724 * @return true if obj1 and obj2 are identical script objects or mirrors of it.
attila@963 725 */
attila@963 726 public static boolean identical(final Object obj1, final Object obj2) {
attila@963 727 final Object o1 = (obj1 instanceof ScriptObjectMirror)?
attila@963 728 ((ScriptObjectMirror)obj1).sobj : obj1;
attila@963 729
attila@963 730 final Object o2 = (obj2 instanceof ScriptObjectMirror)?
attila@963 731 ((ScriptObjectMirror)obj2).sobj : obj2;
attila@963 732
attila@963 733 return o1 == o2;
attila@963 734 }
attila@963 735
aoqi@0 736 // package-privates below this.
aoqi@0 737
aoqi@0 738 ScriptObjectMirror(final ScriptObject sobj, final Global global) {
aoqi@0 739 assert sobj != null : "ScriptObjectMirror on null!";
aoqi@0 740 assert global != null : "home Global is null";
aoqi@0 741
aoqi@0 742 this.sobj = sobj;
aoqi@0 743 this.global = global;
aoqi@0 744 this.strict = global.isStrictContext();
aoqi@0 745 }
aoqi@0 746
aoqi@0 747 // accessors for script engine
aoqi@0 748 ScriptObject getScriptObject() {
aoqi@0 749 return sobj;
aoqi@0 750 }
aoqi@0 751
aoqi@0 752 Global getHomeGlobal() {
aoqi@0 753 return global;
aoqi@0 754 }
aoqi@0 755
attila@962 756 static Object translateUndefined(final Object obj) {
aoqi@0 757 return (obj == ScriptRuntime.UNDEFINED)? null : obj;
aoqi@0 758 }
aoqi@0 759
hannesw@1020 760 private int getCallSiteFlags() {
hannesw@1020 761 return strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
hannesw@1020 762 }
hannesw@1020 763
aoqi@0 764 // internals only below this.
aoqi@0 765 private <V> V inGlobal(final Callable<V> callable) {
aoqi@0 766 final Global oldGlobal = Context.getGlobal();
aoqi@0 767 final boolean globalChanged = (oldGlobal != global);
aoqi@0 768 if (globalChanged) {
aoqi@0 769 Context.setGlobal(global);
aoqi@0 770 }
aoqi@0 771 try {
aoqi@0 772 return callable.call();
aoqi@0 773 } catch (final NashornException ne) {
aoqi@0 774 throw ne.initEcmaError(global);
aoqi@0 775 } catch (final RuntimeException e) {
aoqi@0 776 throw e;
aoqi@0 777 } catch (final Exception e) {
aoqi@0 778 throw new AssertionError("Cannot happen", e);
aoqi@0 779 } finally {
aoqi@0 780 if (globalChanged) {
aoqi@0 781 Context.setGlobal(oldGlobal);
aoqi@0 782 }
aoqi@0 783 }
aoqi@0 784 }
aoqi@0 785
aoqi@0 786 @Override
aoqi@0 787 public double toNumber() {
aoqi@0 788 return inGlobal(new Callable<Double>() {
aoqi@0 789 @Override public Double call() {
aoqi@0 790 return JSType.toNumber(sobj);
aoqi@0 791 }
aoqi@0 792 });
aoqi@0 793 }
aoqi@0 794 }

mercurial