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

Mon, 04 Nov 2013 18:52:22 +0530

author
sundar
date
Mon, 04 Nov 2013 18:52:22 +0530
changeset 665
dcedc753fd09
parent 663
98bab0cdd7bf
child 668
2f07b4234451
permissions
-rw-r--r--

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

mercurial