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

Wed, 23 Oct 2013 17:30:13 +0530

author
sundar
date
Wed, 23 Oct 2013 17:30:13 +0530
changeset 648
5df55690fd5b
parent 645
6f19eb443a47
child 663
98bab0cdd7bf
permissions
-rw-r--r--

8027128: jdk.nashorn.api.scripting.JSObject should be an interface
Reviewed-by: hannesw, attila, jlaskey

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.api.scripting;
jlaskey@3 27
sundar@492 28 import java.security.AccessControlContext;
sundar@41 29 import java.security.AccessController;
sundar@492 30 import java.security.Permissions;
sundar@41 31 import java.security.PrivilegedAction;
sundar@492 32 import java.security.ProtectionDomain;
jlaskey@3 33 import java.util.AbstractMap;
jlaskey@3 34 import java.util.ArrayList;
jlaskey@3 35 import java.util.Collection;
jlaskey@3 36 import java.util.Collections;
sundar@492 37 import java.util.Iterator;
sundar@321 38 import java.util.LinkedHashSet;
jlaskey@3 39 import java.util.List;
jlaskey@3 40 import java.util.Map;
jlaskey@3 41 import java.util.Set;
jlaskey@3 42 import java.util.concurrent.Callable;
sundar@38 43 import javax.script.Bindings;
jlaskey@3 44 import jdk.nashorn.internal.runtime.Context;
sundar@541 45 import jdk.nashorn.internal.runtime.GlobalObject;
attila@644 46 import jdk.nashorn.internal.runtime.JSType;
jlaskey@3 47 import jdk.nashorn.internal.runtime.ScriptFunction;
jlaskey@3 48 import jdk.nashorn.internal.runtime.ScriptObject;
sundar@33 49 import jdk.nashorn.internal.runtime.ScriptRuntime;
jlaskey@3 50
jlaskey@3 51 /**
sundar@546 52 * Mirror object that wraps a given Nashorn Script object.
jlaskey@3 53 */
sundar@648 54 public final class ScriptObjectMirror extends AbstractJSObject implements Bindings {
sundar@492 55 private static AccessControlContext getContextAccCtxt() {
sundar@492 56 final Permissions perms = new Permissions();
sundar@492 57 perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
sundar@492 58 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
sundar@492 59 }
sundar@492 60
sundar@492 61 private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt();
sundar@492 62
jlaskey@3 63 private final ScriptObject sobj;
jlaskey@3 64 private final ScriptObject global;
sundar@541 65 private final boolean strict;
jlaskey@3 66
jlaskey@3 67 @Override
jlaskey@3 68 public boolean equals(final Object other) {
jlaskey@3 69 if (other instanceof ScriptObjectMirror) {
jlaskey@3 70 return sobj.equals(((ScriptObjectMirror)other).sobj);
jlaskey@3 71 }
jlaskey@3 72
jlaskey@3 73 return false;
jlaskey@3 74 }
jlaskey@3 75
jlaskey@3 76 @Override
jlaskey@3 77 public int hashCode() {
jlaskey@3 78 return sobj.hashCode();
jlaskey@3 79 }
jlaskey@3 80
sundar@33 81 @Override
sundar@33 82 public String toString() {
sundar@33 83 return inGlobal(new Callable<String>() {
sundar@33 84 @Override
sundar@33 85 public String call() {
sundar@33 86 return ScriptRuntime.safeToString(sobj);
sundar@33 87 }
sundar@33 88 });
sundar@33 89 }
sundar@33 90
jlaskey@3 91 // JSObject methods
sundar@546 92
jlaskey@3 93 @Override
sundar@546 94 public Object call(final Object thiz, final Object... args) {
sundar@456 95 final ScriptObject oldGlobal = Context.getGlobal();
jlaskey@3 96 final boolean globalChanged = (oldGlobal != global);
jlaskey@3 97
sundar@88 98 try {
sundar@88 99 if (globalChanged) {
sundar@456 100 Context.setGlobal(global);
jlaskey@3 101 }
jlaskey@3 102
sundar@546 103 if (sobj instanceof ScriptFunction) {
sundar@514 104 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
sundar@546 105 final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz;
sundar@546 106 return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global);
jlaskey@3 107 }
jlaskey@3 108
sundar@546 109 throw new RuntimeException("not a function: " + toString());
sundar@88 110 } catch (final RuntimeException | Error e) {
sundar@88 111 throw e;
sundar@88 112 } catch (final Throwable t) {
sundar@88 113 throw new RuntimeException(t);
sundar@88 114 } finally {
sundar@88 115 if (globalChanged) {
sundar@456 116 Context.setGlobal(oldGlobal);
sundar@88 117 }
sundar@88 118 }
jlaskey@3 119 }
jlaskey@3 120
jlaskey@3 121 @Override
sundar@546 122 public Object newObject(final Object... args) {
sundar@456 123 final ScriptObject oldGlobal = Context.getGlobal();
sundar@376 124 final boolean globalChanged = (oldGlobal != global);
sundar@376 125
sundar@376 126 try {
sundar@376 127 if (globalChanged) {
sundar@456 128 Context.setGlobal(global);
sundar@376 129 }
sundar@376 130
sundar@546 131 if (sobj instanceof ScriptFunction) {
sundar@514 132 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
sundar@546 133 return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global);
sundar@376 134 }
sundar@376 135
sundar@546 136 throw new RuntimeException("not a constructor: " + toString());
sundar@376 137 } catch (final RuntimeException | Error e) {
sundar@376 138 throw e;
sundar@376 139 } catch (final Throwable t) {
sundar@376 140 throw new RuntimeException(t);
sundar@376 141 } finally {
sundar@376 142 if (globalChanged) {
sundar@456 143 Context.setGlobal(oldGlobal);
sundar@376 144 }
sundar@376 145 }
sundar@376 146 }
sundar@376 147
sundar@376 148 @Override
jlaskey@3 149 public Object eval(final String s) {
jlaskey@3 150 return inGlobal(new Callable<Object>() {
jlaskey@3 151 @Override
jlaskey@3 152 public Object call() {
sundar@41 153 final Context context = AccessController.doPrivileged(
sundar@41 154 new PrivilegedAction<Context>() {
sundar@41 155 @Override
sundar@41 156 public Context run() {
sundar@41 157 return Context.getContext();
sundar@41 158 }
sundar@492 159 }, GET_CONTEXT_ACC_CTXT);
sundar@41 160 return wrap(context.eval(global, s, null, null, false), global);
jlaskey@3 161 }
jlaskey@3 162 });
jlaskey@3 163 }
jlaskey@3 164
sundar@546 165 public Object callMember(final String functionName, final Object... args) {
sundar@546 166 functionName.getClass(); // null check
sundar@546 167 final ScriptObject oldGlobal = Context.getGlobal();
sundar@546 168 final boolean globalChanged = (oldGlobal != global);
sundar@546 169
sundar@546 170 try {
sundar@546 171 if (globalChanged) {
sundar@546 172 Context.setGlobal(global);
sundar@546 173 }
sundar@546 174
sundar@546 175 final Object val = sobj.get(functionName);
sundar@546 176 if (val instanceof ScriptFunction) {
sundar@546 177 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
sundar@546 178 return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
sundar@546 179 } else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
sundar@546 180 return ((JSObject)val).call(sobj, args);
sundar@546 181 }
sundar@546 182
sundar@546 183 throw new NoSuchMethodException("No such function " + functionName);
sundar@546 184 } catch (final RuntimeException | Error e) {
sundar@546 185 throw e;
sundar@546 186 } catch (final Throwable t) {
sundar@546 187 throw new RuntimeException(t);
sundar@546 188 } finally {
sundar@546 189 if (globalChanged) {
sundar@546 190 Context.setGlobal(oldGlobal);
sundar@546 191 }
sundar@546 192 }
sundar@546 193 }
sundar@546 194
sundar@546 195 @Override
jlaskey@3 196 public Object getMember(final String name) {
sundar@546 197 name.getClass();
sundar@38 198 return inGlobal(new Callable<Object>() {
sundar@38 199 @Override public Object call() {
sundar@38 200 return wrap(sobj.get(name), global);
sundar@38 201 }
sundar@38 202 });
jlaskey@3 203 }
jlaskey@3 204
jlaskey@3 205 @Override
jlaskey@3 206 public Object getSlot(final int index) {
sundar@38 207 return inGlobal(new Callable<Object>() {
sundar@38 208 @Override public Object call() {
sundar@38 209 return wrap(sobj.get(index), global);
sundar@38 210 }
sundar@38 211 });
jlaskey@3 212 }
jlaskey@3 213
jlaskey@3 214 @Override
sundar@546 215 public boolean hasMember(final String name) {
sundar@546 216 name.getClass();
sundar@546 217 return inGlobal(new Callable<Boolean>() {
sundar@546 218 @Override public Boolean call() {
sundar@546 219 return sobj.has(name);
sundar@546 220 }
sundar@546 221 });
sundar@546 222 }
sundar@546 223
sundar@546 224 @Override
sundar@546 225 public boolean hasSlot(final int slot) {
sundar@546 226 return inGlobal(new Callable<Boolean>() {
sundar@546 227 @Override public Boolean call() {
sundar@546 228 return sobj.has(slot);
sundar@546 229 }
sundar@546 230 });
sundar@546 231 }
sundar@546 232
sundar@546 233 @Override
jlaskey@3 234 public void removeMember(final String name) {
sundar@546 235 name.getClass();
jlaskey@3 236 remove(name);
jlaskey@3 237 }
jlaskey@3 238
jlaskey@3 239 @Override
jlaskey@3 240 public void setMember(final String name, final Object value) {
sundar@546 241 name.getClass();
sundar@88 242 put(name, value);
jlaskey@3 243 }
jlaskey@3 244
jlaskey@3 245 @Override
jlaskey@3 246 public void setSlot(final int index, final Object value) {
sundar@38 247 inGlobal(new Callable<Void>() {
sundar@38 248 @Override public Void call() {
sundar@541 249 sobj.set(index, unwrap(value, global), strict);
sundar@38 250 return null;
sundar@38 251 }
sundar@38 252 });
jlaskey@3 253 }
jlaskey@3 254
sundar@546 255 @Override
sundar@546 256 public boolean isInstance(final Object obj) {
sundar@546 257 if (! (obj instanceof ScriptObjectMirror)) {
sundar@546 258 return false;
sundar@546 259 }
sundar@546 260
sundar@546 261 final ScriptObjectMirror instance = (ScriptObjectMirror)obj;
sundar@546 262 // if not belongs to my global scope, return false
sundar@546 263 if (global != instance.global) {
sundar@546 264 return false;
sundar@546 265 }
sundar@546 266
sundar@546 267 return inGlobal(new Callable<Boolean>() {
sundar@546 268 @Override public Boolean call() {
sundar@546 269 return sobj.isInstance(instance.sobj);
sundar@546 270 }
sundar@546 271 });
sundar@546 272 }
sundar@546 273
sundar@546 274 @Override
sundar@546 275 public String getClassName() {
sundar@546 276 return sobj.getClassName();
sundar@546 277 }
sundar@546 278
sundar@546 279 @Override
sundar@546 280 public boolean isFunction() {
sundar@546 281 return sobj instanceof ScriptFunction;
sundar@546 282 }
sundar@546 283
sundar@546 284 @Override
sundar@546 285 public boolean isStrictFunction() {
sundar@546 286 return isFunction() && ((ScriptFunction)sobj).isStrict();
sundar@546 287 }
sundar@546 288
sundar@546 289 @Override
sundar@546 290 public boolean isArray() {
sundar@546 291 return sobj.isArray();
sundar@546 292 }
sundar@546 293
sundar@437 294 // javax.script.Bindings methods
sundar@437 295
jlaskey@3 296 @Override
jlaskey@3 297 public void clear() {
jlaskey@3 298 inGlobal(new Callable<Object>() {
jlaskey@3 299 @Override public Object call() {
sundar@541 300 sobj.clear(strict);
jlaskey@3 301 return null;
sundar@38 302 }
sundar@38 303 });
jlaskey@3 304 }
jlaskey@3 305
jlaskey@3 306 @Override
jlaskey@3 307 public boolean containsKey(final Object key) {
jlaskey@3 308 return inGlobal(new Callable<Boolean>() {
jlaskey@3 309 @Override public Boolean call() {
jlaskey@3 310 return sobj.containsKey(unwrap(key, global));
sundar@38 311 }
sundar@38 312 });
jlaskey@3 313 }
jlaskey@3 314
jlaskey@3 315 @Override
jlaskey@3 316 public boolean containsValue(final Object value) {
jlaskey@3 317 return inGlobal(new Callable<Boolean>() {
jlaskey@3 318 @Override public Boolean call() {
jlaskey@3 319 return sobj.containsValue(unwrap(value, global));
sundar@38 320 }
sundar@38 321 });
jlaskey@3 322 }
jlaskey@3 323
jlaskey@3 324 @Override
sundar@38 325 public Set<Map.Entry<String, Object>> entrySet() {
sundar@38 326 return inGlobal(new Callable<Set<Map.Entry<String, Object>>>() {
sundar@38 327 @Override public Set<Map.Entry<String, Object>> call() {
jlaskey@3 328 final Iterator<String> iter = sobj.propertyIterator();
sundar@321 329 final Set<Map.Entry<String, Object>> entries = new LinkedHashSet<>();
jlaskey@3 330
jlaskey@3 331 while (iter.hasNext()) {
sundar@38 332 final String key = iter.next();
sundar@38 333 final Object value = translateUndefined(wrap(sobj.get(key), global));
jlaskey@3 334 entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
jlaskey@3 335 }
jlaskey@3 336
jlaskey@3 337 return Collections.unmodifiableSet(entries);
jlaskey@3 338 }
jlaskey@3 339 });
jlaskey@3 340 }
jlaskey@3 341
jlaskey@3 342 @Override
jlaskey@3 343 public Object get(final Object key) {
sundar@38 344 return inGlobal(new Callable<Object>() {
sundar@38 345 @Override public Object call() {
sundar@38 346 return translateUndefined(wrap(sobj.get(key), global));
sundar@38 347 }
sundar@38 348 });
jlaskey@3 349 }
jlaskey@3 350
jlaskey@3 351 @Override
jlaskey@3 352 public boolean isEmpty() {
sundar@38 353 return inGlobal(new Callable<Boolean>() {
sundar@38 354 @Override public Boolean call() {
sundar@38 355 return sobj.isEmpty();
sundar@38 356 }
sundar@38 357 });
jlaskey@3 358 }
jlaskey@3 359
jlaskey@3 360 @Override
sundar@38 361 public Set<String> keySet() {
sundar@38 362 return inGlobal(new Callable<Set<String>>() {
sundar@38 363 @Override public Set<String> call() {
sundar@38 364 final Iterator<String> iter = sobj.propertyIterator();
sundar@321 365 final Set<String> keySet = new LinkedHashSet<>();
jlaskey@3 366
sundar@38 367 while (iter.hasNext()) {
sundar@38 368 keySet.add(iter.next());
sundar@38 369 }
sundar@38 370
sundar@38 371 return Collections.unmodifiableSet(keySet);
jlaskey@3 372 }
sundar@38 373 });
jlaskey@3 374 }
jlaskey@3 375
jlaskey@3 376 @Override
sundar@38 377 public Object put(final String key, final Object value) {
sundar@456 378 final ScriptObject oldGlobal = Context.getGlobal();
sundar@88 379 final boolean globalChanged = (oldGlobal != global);
jlaskey@3 380 return inGlobal(new Callable<Object>() {
jlaskey@3 381 @Override public Object call() {
sundar@88 382 final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
sundar@541 383 return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global));
sundar@38 384 }
sundar@38 385 });
jlaskey@3 386 }
jlaskey@3 387
jlaskey@3 388 @Override
sundar@38 389 public void putAll(final Map<? extends String, ? extends Object> map) {
sundar@456 390 final ScriptObject oldGlobal = Context.getGlobal();
sundar@88 391 final boolean globalChanged = (oldGlobal != global);
sundar@38 392 inGlobal(new Callable<Object>() {
sundar@38 393 @Override public Object call() {
sundar@38 394 for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
sundar@88 395 final Object value = entry.getValue();
sundar@88 396 final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
sundar@88 397 sobj.set(entry.getKey(), unwrap(modValue, global), strict);
sundar@38 398 }
sundar@38 399 return null;
jlaskey@3 400 }
sundar@38 401 });
jlaskey@3 402 }
jlaskey@3 403
jlaskey@3 404 @Override
jlaskey@3 405 public Object remove(final Object key) {
jlaskey@3 406 return inGlobal(new Callable<Object>() {
jlaskey@3 407 @Override public Object call() {
sundar@541 408 return wrap(sobj.remove(unwrap(key, global), strict), global);
jlaskey@3 409 }
jlaskey@3 410 });
jlaskey@3 411 }
jlaskey@3 412
sundar@321 413 /**
sundar@321 414 * Delete a property from this object.
sundar@321 415 *
sundar@321 416 * @param key the property to be deleted
sundar@321 417 *
sundar@321 418 * @return if the delete was successful or not
sundar@321 419 */
sundar@321 420 public boolean delete(final Object key) {
sundar@321 421 return inGlobal(new Callable<Boolean>() {
sundar@321 422 @Override public Boolean call() {
sundar@541 423 return sobj.delete(unwrap(key, global), strict);
sundar@321 424 }
sundar@321 425 });
sundar@321 426 }
sundar@321 427
jlaskey@3 428 @Override
jlaskey@3 429 public int size() {
jlaskey@3 430 return inGlobal(new Callable<Integer>() {
jlaskey@3 431 @Override public Integer call() {
jlaskey@3 432 return sobj.size();
jlaskey@3 433 }
jlaskey@3 434 });
jlaskey@3 435 }
jlaskey@3 436
jlaskey@3 437 @Override
jlaskey@3 438 public Collection<Object> values() {
sundar@38 439 return inGlobal(new Callable<Collection<Object>>() {
sundar@38 440 @Override public Collection<Object> call() {
sundar@38 441 final List<Object> values = new ArrayList<>(size());
sundar@38 442 final Iterator<Object> iter = sobj.valueIterator();
jlaskey@3 443
sundar@38 444 while (iter.hasNext()) {
sundar@88 445 values.add(translateUndefined(wrap(iter.next(), global)));
sundar@38 446 }
sundar@38 447
sundar@38 448 return Collections.unmodifiableList(values);
jlaskey@3 449 }
sundar@38 450 });
sundar@38 451 }
jlaskey@3 452
sundar@350 453 // Support for ECMAScript Object API on mirrors
sundar@350 454
sundar@350 455 /**
sundar@350 456 * Return the __proto__ of this object.
sundar@350 457 * @return __proto__ object.
sundar@350 458 */
sundar@350 459 public Object getProto() {
sundar@350 460 return inGlobal(new Callable<Object>() {
sundar@350 461 @Override public Object call() {
sundar@437 462 return wrap(sobj.getProto(), global);
sundar@350 463 }
sundar@350 464 });
sundar@350 465 }
sundar@350 466
sundar@350 467 /**
sundar@513 468 * Set the __proto__ of this object.
sundar@513 469 * @param proto new proto for this object
sundar@513 470 */
sundar@513 471 public void setProto(final Object proto) {
sundar@513 472 inGlobal(new Callable<Void>() {
sundar@513 473 @Override public Void call() {
sundar@513 474 sobj.setProtoCheck(unwrap(proto, global));
sundar@513 475 return null;
sundar@513 476 }
sundar@513 477 });
sundar@513 478 }
sundar@513 479
sundar@513 480 /**
sundar@350 481 * ECMA 8.12.1 [[GetOwnProperty]] (P)
sundar@350 482 *
sundar@350 483 * @param key property key
sundar@350 484 *
sundar@350 485 * @return Returns the Property Descriptor of the named own property of this
sundar@350 486 * object, or undefined if absent.
sundar@350 487 */
sundar@350 488 public Object getOwnPropertyDescriptor(final String key) {
sundar@350 489 return inGlobal(new Callable<Object>() {
sundar@350 490 @Override public Object call() {
sundar@437 491 return wrap(sobj.getOwnPropertyDescriptor(key), global);
sundar@350 492 }
sundar@350 493 });
sundar@350 494 }
sundar@350 495
sundar@350 496 /**
sundar@350 497 * return an array of own property keys associated with the object.
sundar@350 498 *
sundar@350 499 * @param all True if to include non-enumerable keys.
sundar@350 500 * @return Array of keys.
sundar@350 501 */
sundar@350 502 public String[] getOwnKeys(final boolean all) {
sundar@350 503 return inGlobal(new Callable<String[]>() {
sundar@350 504 @Override public String[] call() {
sundar@437 505 return sobj.getOwnKeys(all);
sundar@350 506 }
sundar@350 507 });
sundar@350 508 }
sundar@350 509
sundar@350 510 /**
sundar@350 511 * Flag this script object as non extensible
sundar@350 512 *
sundar@350 513 * @return the object after being made non extensible
sundar@350 514 */
sundar@350 515 public ScriptObjectMirror preventExtensions() {
sundar@350 516 return inGlobal(new Callable<ScriptObjectMirror>() {
sundar@350 517 @Override public ScriptObjectMirror call() {
sundar@437 518 sobj.preventExtensions();
sundar@350 519 return ScriptObjectMirror.this;
sundar@350 520 }
sundar@350 521 });
sundar@350 522 }
sundar@350 523
sundar@350 524 /**
sundar@350 525 * Check if this script object is extensible
sundar@350 526 * @return true if extensible
sundar@350 527 */
sundar@350 528 public boolean isExtensible() {
sundar@350 529 return inGlobal(new Callable<Boolean>() {
sundar@350 530 @Override public Boolean call() {
sundar@437 531 return sobj.isExtensible();
sundar@350 532 }
sundar@350 533 });
sundar@350 534 }
sundar@350 535
sundar@350 536 /**
sundar@350 537 * ECMAScript 15.2.3.8 - seal implementation
sundar@350 538 * @return the sealed script object
sundar@350 539 */
sundar@350 540 public ScriptObjectMirror seal() {
sundar@350 541 return inGlobal(new Callable<ScriptObjectMirror>() {
sundar@350 542 @Override public ScriptObjectMirror call() {
sundar@437 543 sobj.seal();
sundar@350 544 return ScriptObjectMirror.this;
sundar@350 545 }
sundar@350 546 });
sundar@350 547 }
sundar@350 548
sundar@350 549 /**
sundar@350 550 * Check whether this script object is sealed
sundar@350 551 * @return true if sealed
sundar@350 552 */
sundar@350 553 public boolean isSealed() {
sundar@350 554 return inGlobal(new Callable<Boolean>() {
sundar@350 555 @Override public Boolean call() {
sundar@437 556 return sobj.isSealed();
sundar@350 557 }
sundar@350 558 });
sundar@350 559 }
sundar@350 560
sundar@350 561 /**
sundar@350 562 * ECMA 15.2.39 - freeze implementation. Freeze this script object
sundar@350 563 * @return the frozen script object
sundar@350 564 */
sundar@350 565 public ScriptObjectMirror freeze() {
sundar@350 566 return inGlobal(new Callable<ScriptObjectMirror>() {
sundar@350 567 @Override public ScriptObjectMirror call() {
sundar@437 568 sobj.freeze();
sundar@350 569 return ScriptObjectMirror.this;
sundar@350 570 }
sundar@350 571 });
sundar@350 572 }
sundar@350 573
sundar@350 574 /**
sundar@350 575 * Check whether this script object is frozen
sundar@350 576 * @return true if frozen
sundar@350 577 */
sundar@350 578 public boolean isFrozen() {
sundar@350 579 return inGlobal(new Callable<Boolean>() {
sundar@350 580 @Override public Boolean call() {
sundar@437 581 return sobj.isFrozen();
sundar@350 582 }
sundar@350 583 });
sundar@350 584 }
sundar@350 585
sundar@437 586 /**
sundar@350 587 * Utility to check if given object is ECMAScript undefined value
sundar@350 588 *
sundar@350 589 * @param obj object to check
sundar@350 590 * @return true if 'obj' is ECMAScript undefined value
sundar@350 591 */
sundar@350 592 public static boolean isUndefined(final Object obj) {
sundar@350 593 return obj == ScriptRuntime.UNDEFINED;
sundar@350 594 }
sundar@350 595
sundar@350 596 /**
sundar@322 597 * Make a script object mirror on given object if needed.
sundar@322 598 *
sundar@322 599 * @param obj object to be wrapped
sundar@322 600 * @param homeGlobal global to which this object belongs
sundar@322 601 * @return wrapped object
sundar@322 602 */
sundar@322 603 public static Object wrap(final Object obj, final ScriptObject homeGlobal) {
sundar@456 604 return (obj instanceof ScriptObject && homeGlobal != null) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj;
jlaskey@3 605 }
jlaskey@3 606
sundar@322 607 /**
sundar@322 608 * Unwrap a script object mirror if needed.
sundar@322 609 *
sundar@322 610 * @param obj object to be unwrapped
sundar@322 611 * @param homeGlobal global to which this object belongs
sundar@322 612 * @return unwrapped object
sundar@322 613 */
sundar@322 614 public static Object unwrap(final Object obj, final ScriptObject homeGlobal) {
jlaskey@3 615 if (obj instanceof ScriptObjectMirror) {
jlaskey@3 616 final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
jlaskey@3 617 return (mirror.global == homeGlobal)? mirror.sobj : obj;
jlaskey@3 618 }
jlaskey@3 619
jlaskey@3 620 return obj;
jlaskey@3 621 }
jlaskey@3 622
sundar@322 623 /**
sundar@322 624 * Wrap an array of object to script object mirrors if needed.
sundar@322 625 *
sundar@322 626 * @param args array to be unwrapped
sundar@322 627 * @param homeGlobal global to which this object belongs
sundar@322 628 * @return wrapped array
sundar@322 629 */
sundar@322 630 public static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) {
jlaskey@3 631 if (args == null || args.length == 0) {
jlaskey@3 632 return args;
jlaskey@3 633 }
jlaskey@3 634
jlaskey@3 635 final Object[] newArgs = new Object[args.length];
jlaskey@3 636 int index = 0;
jlaskey@3 637 for (final Object obj : args) {
jlaskey@3 638 newArgs[index] = wrap(obj, homeGlobal);
jlaskey@3 639 index++;
jlaskey@3 640 }
jlaskey@3 641 return newArgs;
jlaskey@3 642 }
jlaskey@3 643
sundar@322 644 /**
sundar@322 645 * Unwrap an array of script object mirrors if needed.
sundar@322 646 *
sundar@322 647 * @param args array to be unwrapped
sundar@322 648 * @param homeGlobal global to which this object belongs
sundar@322 649 * @return unwrapped array
sundar@322 650 */
sundar@322 651 public static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) {
jlaskey@3 652 if (args == null || args.length == 0) {
jlaskey@3 653 return args;
jlaskey@3 654 }
jlaskey@3 655
jlaskey@3 656 final Object[] newArgs = new Object[args.length];
jlaskey@3 657 int index = 0;
jlaskey@3 658 for (final Object obj : args) {
jlaskey@3 659 newArgs[index] = unwrap(obj, homeGlobal);
jlaskey@3 660 index++;
jlaskey@3 661 }
jlaskey@3 662 return newArgs;
jlaskey@3 663 }
sundar@322 664
sundar@322 665 // package-privates below this.
sundar@437 666
sundar@437 667 ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
sundar@472 668 assert sobj != null : "ScriptObjectMirror on null!";
sundar@541 669 assert global instanceof GlobalObject : "global is not a GlobalObject";
sundar@472 670
sundar@437 671 this.sobj = sobj;
sundar@437 672 this.global = global;
sundar@541 673 this.strict = ((GlobalObject)global).isStrictContext();
sundar@437 674 }
sundar@437 675
sundar@472 676 // accessors for script engine
sundar@322 677 ScriptObject getScriptObject() {
sundar@322 678 return sobj;
sundar@322 679 }
sundar@322 680
sundar@472 681 ScriptObject getHomeGlobal() {
sundar@472 682 return global;
sundar@472 683 }
sundar@472 684
sundar@322 685 static Object translateUndefined(Object obj) {
sundar@322 686 return (obj == ScriptRuntime.UNDEFINED)? null : obj;
sundar@322 687 }
sundar@437 688
sundar@437 689 // internals only below this.
sundar@437 690 private <V> V inGlobal(final Callable<V> callable) {
sundar@456 691 final ScriptObject oldGlobal = Context.getGlobal();
sundar@437 692 final boolean globalChanged = (oldGlobal != global);
sundar@437 693 if (globalChanged) {
sundar@456 694 Context.setGlobal(global);
sundar@437 695 }
sundar@437 696 try {
sundar@437 697 return callable.call();
sundar@437 698 } catch (final RuntimeException e) {
sundar@437 699 throw e;
sundar@437 700 } catch (final Exception e) {
sundar@437 701 throw new AssertionError("Cannot happen", e);
sundar@437 702 } finally {
sundar@437 703 if (globalChanged) {
sundar@456 704 Context.setGlobal(oldGlobal);
sundar@437 705 }
sundar@437 706 }
sundar@437 707 }
attila@644 708
attila@645 709 @Override
attila@644 710 public double toNumber() {
attila@644 711 return inGlobal(new Callable<Double>() {
attila@644 712 @Override public Double call() {
attila@644 713 return JSType.toNumber(sobj);
attila@644 714 }
attila@644 715 });
attila@644 716 }
jlaskey@3 717 }

mercurial