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

Tue, 20 Jan 2015 12:34:21 +0100

author
attila
date
Tue, 20 Jan 2015 12:34:21 +0100
changeset 1221
a71df7915453
parent 1212
0c0130c5ff1b
child 1231
701c1dcdf733
permissions
-rw-r--r--

8068603: ScriptObjectMirror should reject null/empty string/non-string parameters in Bindings methods
Reviewed-by: hannesw, sundar

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

mercurial