Global.java revision 1483:7cb19fa78763
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.objects; 27 28import static jdk.nashorn.internal.lookup.Lookup.MH; 29import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; 30import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 31import static jdk.nashorn.internal.runtime.JSType.isString; 32import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 33 34import java.io.IOException; 35import java.io.PrintWriter; 36import java.lang.invoke.MethodHandle; 37import java.lang.invoke.MethodHandles; 38import java.lang.invoke.MethodType; 39import java.lang.invoke.SwitchPoint; 40import java.lang.reflect.Field; 41import java.util.ArrayList; 42import java.util.Arrays; 43import java.util.List; 44import java.util.Map; 45import java.util.Objects; 46import java.util.concurrent.Callable; 47import java.util.concurrent.ConcurrentHashMap; 48import javax.script.ScriptContext; 49import javax.script.ScriptEngine; 50import jdk.internal.dynalink.CallSiteDescriptor; 51import jdk.internal.dynalink.StandardOperation; 52import jdk.internal.dynalink.linker.GuardedInvocation; 53import jdk.internal.dynalink.linker.LinkRequest; 54import jdk.nashorn.api.scripting.ClassFilter; 55import jdk.nashorn.api.scripting.ScriptObjectMirror; 56import jdk.nashorn.internal.lookup.Lookup; 57import jdk.nashorn.internal.objects.annotations.Attribute; 58import jdk.nashorn.internal.objects.annotations.Getter; 59import jdk.nashorn.internal.objects.annotations.Property; 60import jdk.nashorn.internal.objects.annotations.ScriptClass; 61import jdk.nashorn.internal.objects.annotations.Setter; 62import jdk.nashorn.internal.runtime.Context; 63import jdk.nashorn.internal.runtime.ECMAErrors; 64import jdk.nashorn.internal.runtime.FindProperty; 65import jdk.nashorn.internal.runtime.GlobalConstants; 66import jdk.nashorn.internal.runtime.GlobalFunctions; 67import jdk.nashorn.internal.runtime.JSType; 68import jdk.nashorn.internal.runtime.NativeJavaPackage; 69import jdk.nashorn.internal.runtime.PropertyDescriptor; 70import jdk.nashorn.internal.runtime.PropertyMap; 71import jdk.nashorn.internal.runtime.Scope; 72import jdk.nashorn.internal.runtime.ScriptEnvironment; 73import jdk.nashorn.internal.runtime.ScriptFunction; 74import jdk.nashorn.internal.runtime.ScriptObject; 75import jdk.nashorn.internal.runtime.ScriptRuntime; 76import jdk.nashorn.internal.runtime.ScriptingFunctions; 77import jdk.nashorn.internal.runtime.Specialization; 78import jdk.nashorn.internal.runtime.arrays.ArrayData; 79import jdk.nashorn.internal.runtime.linker.Bootstrap; 80import jdk.nashorn.internal.runtime.linker.InvokeByName; 81import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 82import jdk.nashorn.internal.runtime.regexp.RegExpResult; 83import jdk.nashorn.internal.scripts.JD; 84import jdk.nashorn.internal.scripts.JO; 85import jdk.nashorn.tools.ShellFunctions; 86 87/** 88 * Representation of global scope. 89 */ 90@ScriptClass("Global") 91public final class Global extends Scope { 92 // This special value is used to flag a lazily initialized global property. 93 // This also serves as placeholder value used in place of a location property 94 // (__FILE__, __DIR__, __LINE__) 95 private static final Object LAZY_SENTINEL = new Object(); 96 97 private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); 98 private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); 99 100 /** 101 * Optimistic builtin names that require switchpoint invalidation 102 * upon assignment. Overly conservative, but works for now, to avoid 103 * any complicated scope checks and especially heavy weight guards 104 * like 105 * 106 * <pre> 107 * public boolean setterGuard(final Object receiver) { 108 * final Global global = Global.instance(); 109 * final ScriptObject sobj = global.getFunctionPrototype(); 110 * final Object apply = sobj.get("apply"); 111 * return apply == receiver; 112 * } 113 * </pre> 114 * 115 * Naturally, checking for builtin classes like NativeFunction is cheaper, 116 * it's when you start adding property checks for said builtins you have 117 * problems with guard speed. 118 */ 119 120 /** Nashorn extension: arguments array */ 121 @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) 122 public Object arguments; 123 124 /** ECMA 15.1.2.2 parseInt (string , radix) */ 125 @Property(attributes = Attribute.NOT_ENUMERABLE) 126 public Object parseInt; 127 128 /** ECMA 15.1.2.3 parseFloat (string) */ 129 @Property(attributes = Attribute.NOT_ENUMERABLE) 130 public Object parseFloat; 131 132 /** ECMA 15.1.2.4 isNaN (number) */ 133 @Property(attributes = Attribute.NOT_ENUMERABLE) 134 public Object isNaN; 135 136 /** ECMA 15.1.2.5 isFinite (number) */ 137 @Property(attributes = Attribute.NOT_ENUMERABLE) 138 public Object isFinite; 139 140 /** ECMA 15.1.3.3 encodeURI */ 141 @Property(attributes = Attribute.NOT_ENUMERABLE) 142 public Object encodeURI; 143 144 /** ECMA 15.1.3.4 encodeURIComponent */ 145 @Property(attributes = Attribute.NOT_ENUMERABLE) 146 public Object encodeURIComponent; 147 148 /** ECMA 15.1.3.1 decodeURI */ 149 @Property(attributes = Attribute.NOT_ENUMERABLE) 150 public Object decodeURI; 151 152 /** ECMA 15.1.3.2 decodeURIComponent */ 153 @Property(attributes = Attribute.NOT_ENUMERABLE) 154 public Object decodeURIComponent; 155 156 /** ECMA B.2.1 escape (string) */ 157 @Property(attributes = Attribute.NOT_ENUMERABLE) 158 public Object escape; 159 160 /** ECMA B.2.2 unescape (string) */ 161 @Property(attributes = Attribute.NOT_ENUMERABLE) 162 public Object unescape; 163 164 /** Nashorn extension: global.print */ 165 @Property(attributes = Attribute.NOT_ENUMERABLE) 166 public Object print; 167 168 /** Nashorn extension: global.load */ 169 @Property(attributes = Attribute.NOT_ENUMERABLE) 170 public Object load; 171 172 /** Nashorn extension: global.loadWithNewGlobal */ 173 @Property(attributes = Attribute.NOT_ENUMERABLE) 174 public Object loadWithNewGlobal; 175 176 /** Nashorn extension: global.exit */ 177 @Property(attributes = Attribute.NOT_ENUMERABLE) 178 public Object exit; 179 180 /** Nashorn extension: global.quit */ 181 @Property(attributes = Attribute.NOT_ENUMERABLE) 182 public Object quit; 183 184 /** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */ 185 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 186 public static final double NaN = Double.NaN; 187 188 /** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */ 189 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 190 public static final double Infinity = Double.POSITIVE_INFINITY; 191 192 /** Value property Undefined of the Global Object - ECMA 15.1.1.3 Undefined */ 193 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 194 public static final Object undefined = UNDEFINED; 195 196 /** ECMA 15.1.2.1 eval(x) */ 197 @Property(attributes = Attribute.NOT_ENUMERABLE) 198 public Object eval; 199 200 /** ECMA 15.1.4.1 Object constructor. */ 201 @Property(name = "Object", attributes = Attribute.NOT_ENUMERABLE) 202 public volatile Object object; 203 204 /** ECMA 15.1.4.2 Function constructor. */ 205 @Property(name = "Function", attributes = Attribute.NOT_ENUMERABLE) 206 public volatile Object function; 207 208 /** ECMA 15.1.4.3 Array constructor. */ 209 @Property(name = "Array", attributes = Attribute.NOT_ENUMERABLE) 210 public volatile Object array; 211 212 /** ECMA 15.1.4.4 String constructor */ 213 @Property(name = "String", attributes = Attribute.NOT_ENUMERABLE) 214 public volatile Object string; 215 216 /** ECMA 15.1.4.5 Boolean constructor */ 217 @Property(name = "Boolean", attributes = Attribute.NOT_ENUMERABLE) 218 public volatile Object _boolean; 219 220 /** ECMA 15.1.4.6 - Number constructor */ 221 @Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE) 222 public volatile Object number; 223 224 /** 225 * Getter for ECMA 15.1.4.7 Date property 226 * 227 * @param self self reference 228 * @return Date property value 229 */ 230 @Getter(name = "Date", attributes = Attribute.NOT_ENUMERABLE) 231 public static Object getDate(final Object self) { 232 final Global global = Global.instanceFrom(self); 233 if (global.date == LAZY_SENTINEL) { 234 global.date = global.getBuiltinDate(); 235 } 236 return global.date; 237 } 238 239 /** 240 * Setter for ECMA 15.1.4.7 Date property 241 * 242 * @param self self reference 243 * @param value value for the Date property 244 */ 245 @Setter(name = "Date", attributes = Attribute.NOT_ENUMERABLE) 246 public static void setDate(final Object self, final Object value) { 247 final Global global = Global.instanceFrom(self); 248 global.date = value; 249 } 250 251 private volatile Object date = LAZY_SENTINEL; 252 253 /** 254 * Getter for ECMA 15.1.4.8 RegExp property 255 * 256 * @param self self reference 257 * @return RegExp property value 258 */ 259 @Getter(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE) 260 public static Object getRegExp(final Object self) { 261 final Global global = Global.instanceFrom(self); 262 if (global.regexp == LAZY_SENTINEL) { 263 global.regexp = global.getBuiltinRegExp(); 264 } 265 return global.regexp; 266 } 267 268 /** 269 * Setter for ECMA 15.1.4.8 RegExp property 270 * 271 * @param self self reference 272 * @param value value for the RegExp property 273 */ 274 @Setter(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE) 275 public static void setRegExp(final Object self, final Object value) { 276 final Global global = Global.instanceFrom(self); 277 global.regexp = value; 278 } 279 280 private volatile Object regexp = LAZY_SENTINEL; 281 282 /** 283 * Getter for ECMA 15.12 - The JSON property 284 * @param self self reference 285 * @return the value of JSON property 286 */ 287 @Getter(name = "JSON", attributes = Attribute.NOT_ENUMERABLE) 288 public static Object getJSON(final Object self) { 289 final Global global = Global.instanceFrom(self); 290 if (global.json == LAZY_SENTINEL) { 291 global.json = global.getBuiltinJSON(); 292 } 293 return global.json; 294 } 295 296 /** 297 * Setter for ECMA 15.12 - The JSON property 298 * @param self self reference 299 * @param value value for the JSON property 300 */ 301 @Setter(name = "JSON", attributes = Attribute.NOT_ENUMERABLE) 302 public static void setJSON(final Object self, final Object value) { 303 final Global global = Global.instanceFrom(self); 304 global.json = value; 305 } 306 307 private volatile Object json = LAZY_SENTINEL; 308 309 /** 310 * Getter for Nashorn extension: global.JSAdapter 311 * @param self self reference 312 * @return value of the JSAdapter property 313 */ 314 @Getter(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE) 315 public static Object getJSAdapter(final Object self) { 316 final Global global = Global.instanceFrom(self); 317 if (global.jsadapter == LAZY_SENTINEL) { 318 global.jsadapter = global.getBuiltinJSAdapter(); 319 } 320 return global.jsadapter; 321 } 322 323 /** 324 * Setter for Nashorn extension: global.JSAdapter 325 * @param self self reference 326 * @param value value for the JSAdapter property 327 */ 328 @Setter(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE) 329 public static void setJSAdapter(final Object self, final Object value) { 330 final Global global = Global.instanceFrom(self); 331 global.jsadapter = value; 332 } 333 334 private volatile Object jsadapter = LAZY_SENTINEL; 335 336 /** ECMA 15.8 - The Math object */ 337 @Property(name = "Math", attributes = Attribute.NOT_ENUMERABLE) 338 public volatile Object math; 339 340 /** Error object */ 341 @Property(name = "Error", attributes = Attribute.NOT_ENUMERABLE) 342 public volatile Object error; 343 344 /** 345 * Getter for the EvalError property 346 * @param self self reference 347 * @return the value of EvalError property 348 */ 349 @Getter(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE) 350 public static Object getEvalError(final Object self) { 351 final Global global = Global.instanceFrom(self); 352 if (global.evalError == LAZY_SENTINEL) { 353 global.evalError = global.getBuiltinEvalError(); 354 } 355 return global.evalError; 356 } 357 358 /** 359 * Setter for the EvalError property 360 * @param self self reference 361 * @param value value of the EvalError property 362 */ 363 @Setter(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE) 364 public static void setEvalError(final Object self, final Object value) { 365 final Global global = Global.instanceFrom(self); 366 global.evalError = value; 367 } 368 369 private volatile Object evalError = LAZY_SENTINEL; 370 371 /** 372 * Getter for the RangeError property. 373 * @param self self reference 374 * @return the value of RangeError property 375 */ 376 @Getter(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE) 377 public static Object getRangeError(final Object self) { 378 final Global global = Global.instanceFrom(self); 379 if (global.rangeError == LAZY_SENTINEL) { 380 global.rangeError = global.getBuiltinRangeError(); 381 } 382 return global.rangeError; 383 } 384 385 386 /** 387 * Setter for the RangeError property. 388 * @param self self reference 389 * @param value value for the RangeError property 390 */ 391 @Setter(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE) 392 public static void setRangeError(final Object self, final Object value) { 393 final Global global = Global.instanceFrom(self); 394 global.rangeError = value; 395 } 396 397 private volatile Object rangeError = LAZY_SENTINEL; 398 399 /** ReferenceError object */ 400 @Property(name = "ReferenceError", attributes = Attribute.NOT_ENUMERABLE) 401 public volatile Object referenceError; 402 403 /** SyntaxError object */ 404 @Property(name = "SyntaxError", attributes = Attribute.NOT_ENUMERABLE) 405 public volatile Object syntaxError; 406 407 /** TypeError object */ 408 @Property(name = "TypeError", attributes = Attribute.NOT_ENUMERABLE) 409 public volatile Object typeError; 410 411 /** 412 * Getter for the URIError property. 413 * @param self self reference 414 * @return the value of URIError property 415 */ 416 @Getter(name = "URIError", attributes = Attribute.NOT_ENUMERABLE) 417 public static Object getURIError(final Object self) { 418 final Global global = Global.instanceFrom(self); 419 if (global.uriError == LAZY_SENTINEL) { 420 global.uriError = global.getBuiltinURIError(); 421 } 422 return global.uriError; 423 } 424 425 /** 426 * Setter for the URIError property. 427 * @param self self reference 428 * @param value value for the URIError property 429 */ 430 @Setter(name = "URIError", attributes = Attribute.NOT_ENUMERABLE) 431 public static void setURIError(final Object self, final Object value) { 432 final Global global = Global.instanceFrom(self); 433 global.uriError = value; 434 } 435 436 private volatile Object uriError = LAZY_SENTINEL; 437 438 /** 439 * Getter for the ArrayBuffer property. 440 * @param self self reference 441 * @return the value of the ArrayBuffer property 442 */ 443 @Getter(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE) 444 public static Object getArrayBuffer(final Object self) { 445 final Global global = Global.instanceFrom(self); 446 if (global.arrayBuffer == LAZY_SENTINEL) { 447 global.arrayBuffer = global.getBuiltinArrayBuffer(); 448 } 449 return global.arrayBuffer; 450 } 451 452 /** 453 * Setter for the ArrayBuffer property. 454 * @param self self reference 455 * @param value value of the ArrayBuffer property 456 */ 457 @Setter(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE) 458 public static void setArrayBuffer(final Object self, final Object value) { 459 final Global global = Global.instanceFrom(self); 460 global.arrayBuffer = value; 461 } 462 463 private volatile Object arrayBuffer; 464 465 /** 466 * Getter for the DataView property. 467 * @param self self reference 468 * @return the value of the DataView property 469 */ 470 @Getter(name = "DataView", attributes = Attribute.NOT_ENUMERABLE) 471 public static Object getDataView(final Object self) { 472 final Global global = Global.instanceFrom(self); 473 if (global.dataView == LAZY_SENTINEL) { 474 global.dataView = global.getBuiltinDataView(); 475 } 476 return global.dataView; 477 } 478 479 480 /** 481 * Setter for the DataView property. 482 * @param self self reference 483 * @param value value of the DataView property 484 */ 485 @Setter(name = "DataView", attributes = Attribute.NOT_ENUMERABLE) 486 public static void setDataView(final Object self, final Object value) { 487 final Global global = Global.instanceFrom(self); 488 global.dataView = value; 489 } 490 491 private volatile Object dataView; 492 493 /** 494 * Getter for the Int8Array property. 495 * @param self self reference 496 * @return the value of the Int8Array property. 497 */ 498 @Getter(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE) 499 public static Object getInt8Array(final Object self) { 500 final Global global = Global.instanceFrom(self); 501 if (global.int8Array == LAZY_SENTINEL) { 502 global.int8Array = global.getBuiltinInt8Array(); 503 } 504 return global.int8Array; 505 } 506 507 /** 508 * Setter for the Int8Array property. 509 * @param self self reference 510 * @param value value of the Int8Array property 511 */ 512 @Setter(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE) 513 public static void setInt8Array(final Object self, final Object value) { 514 final Global global = Global.instanceFrom(self); 515 global.int8Array = value; 516 } 517 518 private volatile Object int8Array; 519 520 /** 521 * Getter for the Uin8Array property. 522 * @param self self reference 523 * @return the value of the Uint8Array property 524 */ 525 @Getter(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE) 526 public static Object getUint8Array(final Object self) { 527 final Global global = Global.instanceFrom(self); 528 if (global.uint8Array == LAZY_SENTINEL) { 529 global.uint8Array = global.getBuiltinUint8Array(); 530 } 531 return global.uint8Array; 532 } 533 534 /** 535 * Setter for the Uin8Array property. 536 * @param self self reference 537 * @param value value of the Uin8Array property 538 */ 539 @Setter(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE) 540 public static void setUint8Array(final Object self, final Object value) { 541 final Global global = Global.instanceFrom(self); 542 global.uint8Array = value; 543 } 544 545 private volatile Object uint8Array; 546 547 /** 548 * Getter for the Uint8ClampedArray property. 549 * @param self self reference 550 * @return the value of the Uint8ClampedArray property 551 */ 552 @Getter(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE) 553 public static Object getUint8ClampedArray(final Object self) { 554 final Global global = Global.instanceFrom(self); 555 if (global.uint8ClampedArray == LAZY_SENTINEL) { 556 global.uint8ClampedArray = global.getBuiltinUint8ClampedArray(); 557 } 558 return global.uint8ClampedArray; 559 } 560 561 /** 562 * Setter for the Uint8ClampedArray property. 563 * @param self self reference 564 * @param value value of the Uint8ClampedArray property 565 */ 566 @Setter(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE) 567 public static void setUint8ClampedArray(final Object self, final Object value) { 568 final Global global = Global.instanceFrom(self); 569 global.uint8ClampedArray = value; 570 } 571 572 private volatile Object uint8ClampedArray; 573 574 /** 575 * Getter for the Int16Array property. 576 * @param self self reference 577 * @return the value of the Int16Array property 578 */ 579 @Getter(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE) 580 public static Object getInt16Array(final Object self) { 581 final Global global = Global.instanceFrom(self); 582 if (global.int16Array == LAZY_SENTINEL) { 583 global.int16Array = global.getBuiltinInt16Array(); 584 } 585 return global.int16Array; 586 } 587 588 /** 589 * Setter for the Int16Array property. 590 * @param self self reference 591 * @param value value of the Int16Array property 592 */ 593 @Setter(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE) 594 public static void setInt16Array(final Object self, final Object value) { 595 final Global global = Global.instanceFrom(self); 596 global.int16Array = value; 597 } 598 599 private volatile Object int16Array; 600 601 /** 602 * Getter for the Uint16Array property. 603 * @param self self reference 604 * @return the value of the Uint16Array property 605 */ 606 @Getter(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE) 607 public static Object getUint16Array(final Object self) { 608 final Global global = Global.instanceFrom(self); 609 if (global.uint16Array == LAZY_SENTINEL) { 610 global.uint16Array = global.getBuiltinUint16Array(); 611 } 612 return global.uint16Array; 613 } 614 615 /** 616 * Setter for the Uint16Array property. 617 * @param self self reference 618 * @param value value of the Uint16Array property 619 */ 620 @Setter(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE) 621 public static void setUint16Array(final Object self, final Object value) { 622 final Global global = Global.instanceFrom(self); 623 global.uint16Array = value; 624 } 625 626 private volatile Object uint16Array; 627 628 /** 629 * Getter for the Int32Array property. 630 * 631 * @param self self reference 632 * @return the value of the Int32Array property 633 */ 634 @Getter(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE) 635 public static Object getInt32Array(final Object self) { 636 final Global global = Global.instanceFrom(self); 637 if (global.int32Array == LAZY_SENTINEL) { 638 global.int32Array = global.getBuiltinInt32Array(); 639 } 640 return global.int32Array; 641 } 642 643 644 /** 645 * Setter for the Int32Array property. 646 * 647 * @param self self reference 648 * @param value value of the Int32Array property 649 */ 650 @Setter(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE) 651 public static void setInt32Array(final Object self, final Object value) { 652 final Global global = Global.instanceFrom(self); 653 global.int32Array = value; 654 } 655 656 private volatile Object int32Array; 657 658 /** 659 * Getter of the Uint32Array property. 660 * 661 * @param self self reference 662 * @return the value of the Uint32Array property 663 */ 664 @Getter(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE) 665 public static Object getUint32Array(final Object self) { 666 final Global global = Global.instanceFrom(self); 667 if (global.uint32Array == LAZY_SENTINEL) { 668 global.uint32Array = global.getBuiltinUint32Array(); 669 } 670 return global.uint32Array; 671 } 672 673 674 /** 675 * Setter of the Uint32Array property. 676 * 677 * @param self self reference 678 * @param value value of the Uint32Array property 679 */ 680 @Setter(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE) 681 public static void setUint32Array(final Object self, final Object value) { 682 final Global global = Global.instanceFrom(self); 683 global.uint32Array = value; 684 } 685 686 private volatile Object uint32Array; 687 688 /** 689 * Getter for the Float32Array property. 690 * 691 * @param self self reference 692 * @return the value of the Float32Array property 693 */ 694 @Getter(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE) 695 public static Object getFloat32Array(final Object self) { 696 final Global global = Global.instanceFrom(self); 697 if (global.float32Array == LAZY_SENTINEL) { 698 global.float32Array = global.getBuiltinFloat32Array(); 699 } 700 return global.float32Array; 701 } 702 703 /** 704 * Setter for the Float32Array property. 705 * 706 * @param self self reference 707 * @param value value of the Float32Array property 708 */ 709 @Setter(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE) 710 public static void setFloat32Array(final Object self, final Object value) { 711 final Global global = Global.instanceFrom(self); 712 global.float32Array = value; 713 } 714 715 private volatile Object float32Array; 716 717 /** 718 * Getter for the Float64Array property. 719 * 720 * @param self self reference 721 * @return the value of the Float64Array property 722 */ 723 @Getter(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE) 724 public static Object getFloat64Array(final Object self) { 725 final Global global = Global.instanceFrom(self); 726 if (global.float64Array == LAZY_SENTINEL) { 727 global.float64Array = global.getBuiltinFloat64Array(); 728 } 729 return global.float64Array; 730 } 731 732 /** 733 * Setter for the Float64Array property. 734 * 735 * @param self self reference 736 * @param value value of the Float64Array property 737 */ 738 @Setter(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE) 739 public static void setFloat64Array(final Object self, final Object value) { 740 final Global global = Global.instanceFrom(self); 741 global.float64Array = value; 742 } 743 744 private volatile Object float64Array; 745 746 /** Nashorn extension: Java access - global.Packages */ 747 @Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE) 748 public volatile Object packages; 749 750 /** Nashorn extension: Java access - global.com */ 751 @Property(attributes = Attribute.NOT_ENUMERABLE) 752 public volatile Object com; 753 754 /** Nashorn extension: Java access - global.edu */ 755 @Property(attributes = Attribute.NOT_ENUMERABLE) 756 public volatile Object edu; 757 758 /** Nashorn extension: Java access - global.java */ 759 @Property(attributes = Attribute.NOT_ENUMERABLE) 760 public volatile Object java; 761 762 /** Nashorn extension: Java access - global.javafx */ 763 @Property(attributes = Attribute.NOT_ENUMERABLE) 764 public volatile Object javafx; 765 766 /** Nashorn extension: Java access - global.javax */ 767 @Property(attributes = Attribute.NOT_ENUMERABLE) 768 public volatile Object javax; 769 770 /** Nashorn extension: Java access - global.org */ 771 @Property(attributes = Attribute.NOT_ENUMERABLE) 772 public volatile Object org; 773 774 /** 775 * Getter for the Nashorn extension: Java access - global.javaImporter. 776 * 777 * @param self self reference 778 * @return the value of the JavaImporter property 779 */ 780 @Getter(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE) 781 public static Object getJavaImporter(final Object self) { 782 final Global global = Global.instanceFrom(self); 783 if (global.javaImporter == LAZY_SENTINEL) { 784 global.javaImporter = global.getBuiltinJavaImporter(); 785 } 786 return global.javaImporter; 787 } 788 789 /** 790 * Setter for the Nashorn extension: Java access - global.javaImporter. 791 * 792 * @param self self reference 793 * @param value value of the JavaImporter property 794 */ 795 @Setter(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE) 796 public static void setJavaImporter(final Object self, final Object value) { 797 final Global global = Global.instanceFrom(self); 798 global.javaImporter = value; 799 } 800 801 private volatile Object javaImporter; 802 803 /** 804 * Getter for the Nashorn extension: global.Java property. 805 * 806 * @param self self reference 807 * @return the value of the Java property 808 */ 809 @Getter(name = "Java", attributes = Attribute.NOT_ENUMERABLE) 810 public static Object getJavaApi(final Object self) { 811 final Global global = Global.instanceFrom(self); 812 if (global.javaApi == LAZY_SENTINEL) { 813 global.javaApi = global.getBuiltinJavaApi(); 814 } 815 return global.javaApi; 816 } 817 818 /** 819 * Setter for the Nashorn extension: global.Java property. 820 * 821 * @param self self reference 822 * @param value value of the Java property 823 */ 824 @Setter(name = "Java", attributes = Attribute.NOT_ENUMERABLE) 825 public static void setJavaApi(final Object self, final Object value) { 826 final Global global = Global.instanceFrom(self); 827 global.javaApi = value; 828 } 829 830 private volatile Object javaApi; 831 832 /** Nashorn extension: current script's file name */ 833 @Property(name = "__FILE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 834 public static final Object __FILE__ = LAZY_SENTINEL; 835 836 /** Nashorn extension: current script's directory */ 837 @Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 838 public static final Object __DIR__ = LAZY_SENTINEL; 839 840 /** Nashorn extension: current source line number being executed */ 841 @Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 842 public static final Object __LINE__ = LAZY_SENTINEL; 843 844 private volatile NativeDate DEFAULT_DATE; 845 846 /** Used as Date.prototype's default value */ 847 NativeDate getDefaultDate() { 848 return DEFAULT_DATE; 849 } 850 851 private volatile NativeRegExp DEFAULT_REGEXP; 852 853 /** Used as RegExp.prototype's default value */ 854 NativeRegExp getDefaultRegExp() { 855 return DEFAULT_REGEXP; 856 } 857 858 /* 859 * Built-in constructor objects: Even if user changes dynamic values of 860 * "Object", "Array" etc., we still want to keep original values of these 861 * constructors here. For example, we need to be able to create array, 862 * regexp literals even after user overwrites global "Array" or "RegExp" 863 * constructor - see also ECMA 262 spec. Annex D. 864 */ 865 private ScriptFunction builtinFunction; 866 private ScriptFunction builtinObject; 867 private ScriptFunction builtinArray; 868 private ScriptFunction builtinBoolean; 869 private ScriptFunction builtinDate; 870 private ScriptObject builtinJSON; 871 private ScriptFunction builtinJSAdapter; 872 private ScriptObject builtinMath; 873 private ScriptFunction builtinNumber; 874 private ScriptFunction builtinRegExp; 875 private ScriptFunction builtinString; 876 private ScriptFunction builtinError; 877 private ScriptFunction builtinEval; 878 private ScriptFunction builtinEvalError; 879 private ScriptFunction builtinRangeError; 880 private ScriptFunction builtinReferenceError; 881 private ScriptFunction builtinSyntaxError; 882 private ScriptFunction builtinTypeError; 883 private ScriptFunction builtinURIError; 884 private ScriptObject builtinPackages; 885 private ScriptObject builtinCom; 886 private ScriptObject builtinEdu; 887 private ScriptObject builtinJava; 888 private ScriptObject builtinJavafx; 889 private ScriptObject builtinJavax; 890 private ScriptObject builtinOrg; 891 private ScriptFunction builtinJavaImporter; 892 private ScriptObject builtinJavaApi; 893 private ScriptFunction builtinArrayBuffer; 894 private ScriptFunction builtinDataView; 895 private ScriptFunction builtinInt8Array; 896 private ScriptFunction builtinUint8Array; 897 private ScriptFunction builtinUint8ClampedArray; 898 private ScriptFunction builtinInt16Array; 899 private ScriptFunction builtinUint16Array; 900 private ScriptFunction builtinInt32Array; 901 private ScriptFunction builtinUint32Array; 902 private ScriptFunction builtinFloat32Array; 903 private ScriptFunction builtinFloat64Array; 904 905 /* 906 * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object 907 */ 908 private ScriptFunction typeErrorThrower; 909 910 // Used to store the last RegExp result to support deprecated RegExp constructor properties 911 private RegExpResult lastRegExpResult; 912 913 private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); 914 private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); 915 private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); 916 private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); 917 private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); 918 private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); 919 private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); 920 private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class); 921 922 // initialized by nasgen 923 private static PropertyMap $nasgenmap$; 924 925 // context to which this global belongs to 926 private final Context context; 927 928 // current ScriptContext to use - can be null. 929 private ThreadLocal<ScriptContext> scontext; 930 // current ScriptEngine associated - can be null. 931 private ScriptEngine engine; 932 933 // ES6 global lexical scope. 934 private final LexicalScope lexicalScope; 935 936 // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope. 937 private SwitchPoint lexicalScopeSwitchPoint; 938 939 /** 940 * Set the current script context 941 * @param ctxt script context 942 */ 943 public void setScriptContext(final ScriptContext ctxt) { 944 assert scontext != null; 945 scontext.set(ctxt); 946 } 947 948 /** 949 * Get the current script context 950 * @return current script context 951 */ 952 public ScriptContext getScriptContext() { 953 assert scontext != null; 954 return scontext.get(); 955 } 956 957 private ScriptContext currentContext() { 958 final ScriptContext sc = scontext != null? scontext.get() : null; 959 return (sc != null)? sc : (engine != null? engine.getContext() : null); 960 } 961 962 @Override 963 protected Context getContext() { 964 return context; 965 } 966 967 @Override 968 protected boolean useDualFields() { 969 return context.useDualFields(); 970 } 971 972 // performs initialization checks for Global constructor and returns the 973 // PropertyMap, if everything is fine. 974 private static PropertyMap checkAndGetMap(final Context context) { 975 // security check first 976 final SecurityManager sm = System.getSecurityManager(); 977 if (sm != null) { 978 sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL)); 979 } 980 981 Objects.requireNonNull(context); 982 983 return $nasgenmap$; 984 } 985 986 /** 987 * Constructor 988 * 989 * @param context the context 990 */ 991 public Global(final Context context) { 992 super(checkAndGetMap(context)); 993 this.context = context; 994 this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null; 995 } 996 997 /** 998 * Script access to "current" Global instance 999 * 1000 * @return the global singleton 1001 */ 1002 public static Global instance() { 1003 return Objects.requireNonNull(Context.getGlobal()); 1004 } 1005 1006 private static Global instanceFrom(final Object self) { 1007 return self instanceof Global? (Global)self : instance(); 1008 } 1009 1010 /** 1011 * Check if we have a Global instance 1012 * @return true if one exists 1013 */ 1014 public static boolean hasInstance() { 1015 return Context.getGlobal() != null; 1016 } 1017 1018 /** 1019 * Script access to {@link ScriptEnvironment} 1020 * 1021 * @return the script environment 1022 */ 1023 static ScriptEnvironment getEnv() { 1024 return instance().getContext().getEnv(); 1025 } 1026 1027 /** 1028 * Script access to {@link Context} 1029 * 1030 * @return the context 1031 */ 1032 static Context getThisContext() { 1033 return instance().getContext(); 1034 } 1035 1036 // Runtime interface to Global 1037 1038 /** 1039 * Is there a class filter in the current Context? 1040 * @return class filter 1041 */ 1042 public ClassFilter getClassFilter() { 1043 return context.getClassFilter(); 1044 } 1045 1046 /** 1047 * Is this global of the given Context? 1048 * @param ctxt the context 1049 * @return true if this global belongs to the given Context 1050 */ 1051 public boolean isOfContext(final Context ctxt) { 1052 return this.context == ctxt; 1053 } 1054 1055 /** 1056 * Does this global belong to a strict Context? 1057 * @return true if this global belongs to a strict Context 1058 */ 1059 public boolean isStrictContext() { 1060 return context.getEnv()._strict; 1061 } 1062 1063 /** 1064 * Initialize standard builtin objects like "Object", "Array", "Function" etc. 1065 * as well as our extension builtin objects like "Java", "JSAdapter" as properties 1066 * of the global scope object. 1067 * 1068 * @param eng ScriptEngine to initialize 1069 */ 1070 public void initBuiltinObjects(final ScriptEngine eng) { 1071 if (this.builtinObject != null) { 1072 // already initialized, just return 1073 return; 1074 } 1075 1076 this.engine = eng; 1077 if (this.engine != null) { 1078 this.scontext = new ThreadLocal<>(); 1079 } 1080 init(eng); 1081 } 1082 1083 /** 1084 * Wrap a Java object as corresponding script object 1085 * 1086 * @param obj object to wrap 1087 * @return wrapped object 1088 */ 1089 public Object wrapAsObject(final Object obj) { 1090 if (obj instanceof Boolean) { 1091 return new NativeBoolean((Boolean)obj, this); 1092 } else if (obj instanceof Number) { 1093 return new NativeNumber(((Number)obj).doubleValue(), this); 1094 } else if (isString(obj)) { 1095 return new NativeString((CharSequence)obj, this); 1096 } else if (obj instanceof Object[]) { // extension 1097 return new NativeArray(ArrayData.allocate((Object[])obj), this); 1098 } else if (obj instanceof double[]) { // extension 1099 return new NativeArray(ArrayData.allocate((double[])obj), this); 1100 } else if (obj instanceof long[]) { 1101 return new NativeArray(ArrayData.allocate((long[])obj), this); 1102 } else if (obj instanceof int[]) { 1103 return new NativeArray(ArrayData.allocate((int[]) obj), this); 1104 } else if (obj instanceof ArrayData) { 1105 return new NativeArray((ArrayData) obj, this); 1106 } else { 1107 // FIXME: more special cases? Map? List? 1108 return obj; 1109 } 1110 } 1111 1112 /** 1113 * Lookup helper for JS primitive types 1114 * 1115 * @param request the link request for the dynamic call site. 1116 * @param self self reference 1117 * 1118 * @return guarded invocation 1119 */ 1120 public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) { 1121 if (isString(self)) { 1122 return NativeString.lookupPrimitive(request, self); 1123 } else if (self instanceof Number) { 1124 return NativeNumber.lookupPrimitive(request, self); 1125 } else if (self instanceof Boolean) { 1126 return NativeBoolean.lookupPrimitive(request, self); 1127 } 1128 throw new IllegalArgumentException("Unsupported primitive: " + self); 1129 } 1130 1131 /** 1132 * Returns a method handle that creates a wrapper object for a JS primitive value. 1133 * 1134 * @param self receiver object 1135 * @return method handle to create wrapper objects for primitive receiver 1136 */ 1137 public static MethodHandle getPrimitiveWrapFilter(final Object self) { 1138 if (isString(self)) { 1139 return NativeString.WRAPFILTER; 1140 } else if (self instanceof Number) { 1141 return NativeNumber.WRAPFILTER; 1142 } else if (self instanceof Boolean) { 1143 return NativeBoolean.WRAPFILTER; 1144 } 1145 throw new IllegalArgumentException("Unsupported primitive: " + self); 1146 } 1147 1148 1149 /** 1150 * Create a new empty script object 1151 * 1152 * @return the new ScriptObject 1153 */ 1154 public ScriptObject newObject() { 1155 return useDualFields() ? new JD(getObjectPrototype()) : new JO(getObjectPrototype()); 1156 } 1157 1158 /** 1159 * Default value of given type 1160 * 1161 * @param sobj script object 1162 * @param typeHint type hint 1163 * 1164 * @return default value 1165 */ 1166 public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) { 1167 // When the [[DefaultValue]] internal method of O is called with no hint, 1168 // then it behaves as if the hint were Number, unless O is a Date object 1169 // in which case it behaves as if the hint were String. 1170 Class<?> hint = typeHint; 1171 if (hint == null) { 1172 hint = Number.class; 1173 } 1174 1175 try { 1176 if (hint == String.class) { 1177 1178 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 1179 1180 if (Bootstrap.isCallable(toString)) { 1181 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 1182 if (JSType.isPrimitive(value)) { 1183 return value; 1184 } 1185 } 1186 1187 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 1188 if (Bootstrap.isCallable(valueOf)) { 1189 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 1190 if (JSType.isPrimitive(value)) { 1191 return value; 1192 } 1193 } 1194 throw typeError(this, "cannot.get.default.string"); 1195 } 1196 1197 if (hint == Number.class) { 1198 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 1199 if (Bootstrap.isCallable(valueOf)) { 1200 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 1201 if (JSType.isPrimitive(value)) { 1202 return value; 1203 } 1204 } 1205 1206 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 1207 if (Bootstrap.isCallable(toString)) { 1208 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 1209 if (JSType.isPrimitive(value)) { 1210 return value; 1211 } 1212 } 1213 1214 throw typeError(this, "cannot.get.default.number"); 1215 } 1216 } catch (final RuntimeException | Error e) { 1217 throw e; 1218 } catch (final Throwable t) { 1219 throw new RuntimeException(t); 1220 } 1221 1222 return UNDEFINED; 1223 } 1224 1225 /** 1226 * Is the given ScriptObject an ECMAScript Error object? 1227 * 1228 * @param sobj the object being checked 1229 * @return true if sobj is an Error object 1230 */ 1231 public boolean isError(final ScriptObject sobj) { 1232 final ScriptObject errorProto = getErrorPrototype(); 1233 ScriptObject proto = sobj.getProto(); 1234 while (proto != null) { 1235 if (proto == errorProto) { 1236 return true; 1237 } 1238 proto = proto.getProto(); 1239 } 1240 return false; 1241 } 1242 1243 /** 1244 * Create a new ECMAScript Error object. 1245 * 1246 * @param msg error message 1247 * @return newly created Error object 1248 */ 1249 public ScriptObject newError(final String msg) { 1250 return new NativeError(msg, this); 1251 } 1252 1253 /** 1254 * Create a new ECMAScript EvalError object. 1255 * 1256 * @param msg error message 1257 * @return newly created EvalError object 1258 */ 1259 public ScriptObject newEvalError(final String msg) { 1260 return new NativeEvalError(msg, this); 1261 } 1262 1263 /** 1264 * Create a new ECMAScript RangeError object. 1265 * 1266 * @param msg error message 1267 * @return newly created RangeError object 1268 */ 1269 public ScriptObject newRangeError(final String msg) { 1270 return new NativeRangeError(msg, this); 1271 } 1272 1273 /** 1274 * Create a new ECMAScript ReferenceError object. 1275 * 1276 * @param msg error message 1277 * @return newly created ReferenceError object 1278 */ 1279 public ScriptObject newReferenceError(final String msg) { 1280 return new NativeReferenceError(msg, this); 1281 } 1282 1283 /** 1284 * Create a new ECMAScript SyntaxError object. 1285 * 1286 * @param msg error message 1287 * @return newly created SyntaxError object 1288 */ 1289 public ScriptObject newSyntaxError(final String msg) { 1290 return new NativeSyntaxError(msg, this); 1291 } 1292 1293 /** 1294 * Create a new ECMAScript TypeError object. 1295 * 1296 * @param msg error message 1297 * @return newly created TypeError object 1298 */ 1299 public ScriptObject newTypeError(final String msg) { 1300 return new NativeTypeError(msg, this); 1301 } 1302 1303 /** 1304 * Create a new ECMAScript URIError object. 1305 * 1306 * @param msg error message 1307 * @return newly created URIError object 1308 */ 1309 public ScriptObject newURIError(final String msg) { 1310 return new NativeURIError(msg, this); 1311 } 1312 1313 /** 1314 * Create a new ECMAScript GenericDescriptor object. 1315 * 1316 * @param configurable is the property configurable? 1317 * @param enumerable is the property enumerable? 1318 * @return newly created GenericDescriptor object 1319 */ 1320 public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) { 1321 return new GenericPropertyDescriptor(configurable, enumerable, this); 1322 } 1323 1324 /** 1325 * Create a new ECMAScript DatePropertyDescriptor object. 1326 * 1327 * @param value of the data property 1328 * @param configurable is the property configurable? 1329 * @param enumerable is the property enumerable? 1330 * @param writable is the property writable? 1331 * @return newly created DataPropertyDescriptor object 1332 */ 1333 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { 1334 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this); 1335 } 1336 1337 /** 1338 * Create a new ECMAScript AccessorPropertyDescriptor object. 1339 * 1340 * @param get getter function of the user accessor property 1341 * @param set setter function of the user accessor property 1342 * @param configurable is the property configurable? 1343 * @param enumerable is the property enumerable? 1344 * @return newly created AccessorPropertyDescriptor object 1345 */ 1346 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { 1347 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this); 1348 1349 if (get == null) { 1350 desc.delete(PropertyDescriptor.GET, false); 1351 } 1352 1353 if (set == null) { 1354 desc.delete(PropertyDescriptor.SET, false); 1355 } 1356 1357 return desc; 1358 } 1359 1360 private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) { 1361 final T obj = map.get(key); 1362 if (obj != null) { 1363 return obj; 1364 } 1365 1366 try { 1367 final T newObj = creator.call(); 1368 final T existingObj = map.putIfAbsent(key, newObj); 1369 return existingObj != null ? existingObj : newObj; 1370 } catch (final Exception exp) { 1371 throw new RuntimeException(exp); 1372 } 1373 } 1374 1375 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>(); 1376 1377 1378 /** 1379 * Get cached InvokeByName object for the given key 1380 * @param key key to be associated with InvokeByName object 1381 * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) 1382 * @return InvokeByName object associated with the key. 1383 */ 1384 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) { 1385 return getLazilyCreatedValue(key, creator, namedInvokers); 1386 } 1387 1388 private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>(); 1389 1390 /** 1391 * Get cached dynamic method handle for the given key 1392 * @param key key to be associated with dynamic method handle 1393 * @param creator if method handle is absent 'creator' is called to make one (lazy init) 1394 * @return dynamic method handle associated with the key. 1395 */ 1396 public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) { 1397 return getLazilyCreatedValue(key, creator, dynamicInvokers); 1398 } 1399 1400 /** 1401 * Hook to search missing variables in ScriptContext if available 1402 * @param self used to detect if scope call or not (this function is 'strict') 1403 * @param name name of the variable missing 1404 * @return value of the missing variable or undefined (or TypeError for scope search) 1405 */ 1406 public static Object __noSuchProperty__(final Object self, final Object name) { 1407 final Global global = Global.instance(); 1408 final ScriptContext sctxt = global.currentContext(); 1409 final String nameStr = name.toString(); 1410 1411 if (sctxt != null) { 1412 final int scope = sctxt.getAttributesScope(nameStr); 1413 if (scope != -1) { 1414 return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global); 1415 } 1416 } 1417 1418 switch (nameStr) { 1419 case "context": 1420 return sctxt; 1421 case "engine": 1422 return global.engine; 1423 default: 1424 break; 1425 } 1426 1427 if (self == UNDEFINED) { 1428 // scope access and so throw ReferenceError 1429 throw referenceError(global, "not.defined", nameStr); 1430 } 1431 1432 return UNDEFINED; 1433 } 1434 1435 /** 1436 * This is the eval used when 'indirect' eval call is made. 1437 * 1438 * var global = this; 1439 * global.eval("print('hello')"); 1440 * 1441 * @param self eval scope 1442 * @param str eval string 1443 * 1444 * @return the result of eval 1445 */ 1446 public static Object eval(final Object self, final Object str) { 1447 return directEval(self, str, Global.instanceFrom(self), UNDEFINED, false); 1448 } 1449 1450 /** 1451 * Direct eval 1452 * 1453 * @param self The scope of eval passed as 'self' 1454 * @param str Evaluated code 1455 * @param callThis "this" to be passed to the evaluated code 1456 * @param location location of the eval call 1457 * @param strict is eval called from a strict mode code? 1458 * 1459 * @return the return value of the eval 1460 * 1461 * This is directly invoked from generated when eval(code) is called in user code 1462 */ 1463 public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) { 1464 if (!isString(str)) { 1465 return str; 1466 } 1467 final Global global = Global.instanceFrom(self); 1468 final ScriptObject scope = self instanceof ScriptObject && ((ScriptObject)self).isScope() ? (ScriptObject)self : global; 1469 1470 return global.getContext().eval(scope, str.toString(), callThis, location, strict, true); 1471 } 1472 1473 /** 1474 * Global print implementation - Nashorn extension 1475 * 1476 * @param self scope 1477 * @param objects arguments to print 1478 * 1479 * @return result of print (undefined) 1480 */ 1481 public static Object print(final Object self, final Object... objects) { 1482 return Global.instanceFrom(self).printImpl(false, objects); 1483 } 1484 1485 /** 1486 * Global println implementation - Nashorn extension 1487 * 1488 * @param self scope 1489 * @param objects arguments to print 1490 * 1491 * @return result of println (undefined) 1492 */ 1493 public static Object println(final Object self, final Object... objects) { 1494 return Global.instanceFrom(self).printImpl(true, objects); 1495 } 1496 1497 /** 1498 * Global load implementation - Nashorn extension. 1499 * 1500 * <p> 1501 * load builtin loads the given script. Script source can be a URL or a File 1502 * or a script object with name and script properties. Evaluated code gets 1503 * global object "this" and uses global object as scope for evaluation. 1504 * </p> 1505 * <p> 1506 * If self is undefined or null or global, then global object is used 1507 * as scope as well as "this" for the evaluated code. If self is any other 1508 * object, then it is indirect load call. With indirect load call, the 1509 * properties of scope are available to evaluated script as variables. Also, 1510 * global scope properties are accessible. Any var, function definition in 1511 * evaluated script goes into an object that is not accessible to user scripts. 1512 * </p> 1513 * Thus the indirect load call is equivalent to the following: 1514 * <pre> 1515 * <code> 1516 * (function (scope, source) { 1517 * with(scope) { 1518 * eval(<script_from_source>); 1519 * } 1520 * })(self, source); 1521 * </code> 1522 * </pre> 1523 * 1524 * @param self scope to use for the script evaluation 1525 * @param source script source 1526 * 1527 * @return result of load (may be undefined) 1528 * 1529 * @throws IOException if source could not be read 1530 */ 1531 public static Object load(final Object self, final Object source) throws IOException { 1532 final Global global = Global.instanceFrom(self); 1533 return global.getContext().load(self, source); 1534 } 1535 1536 /** 1537 * Global loadWithNewGlobal implementation - Nashorn extension. 1538 * 1539 * loadWithNewGlobal builtin loads the given script from a URL or a File 1540 * or a script object with name and script properties. Evaluated code gets 1541 * new global object "this" and uses that new global object as scope for evaluation. 1542 * 1543 * @param self self This value is ignored by this function 1544 * @param args optional arguments to be passed to the loaded script 1545 * 1546 * @return result of load (may be undefined) 1547 * 1548 * @throws IOException if source could not be read 1549 */ 1550 public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException { 1551 final Global global = Global.instanceFrom(self); 1552 final int length = args.length; 1553 final boolean hasArgs = 0 < length; 1554 final Object from = hasArgs ? args[0] : UNDEFINED; 1555 final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args; 1556 1557 return global.getContext().loadWithNewGlobal(from, arguments); 1558 } 1559 1560 /** 1561 * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script 1562 * 1563 * @param self self reference 1564 * @param code exit code 1565 * 1566 * @return undefined (will never be reached) 1567 */ 1568 public static Object exit(final Object self, final Object code) { 1569 System.exit(JSType.toInt32(code)); 1570 return UNDEFINED; 1571 } 1572 1573 // builtin prototype accessors 1574 1575 /** 1576 * Get the builtin Object prototype. 1577 * @return the object prototype. 1578 */ 1579 public ScriptObject getObjectPrototype() { 1580 return ScriptFunction.getPrototype(builtinObject); 1581 } 1582 1583 /** 1584 * Get the builtin Function prototype. 1585 * @return the Function.prototype. 1586 */ 1587 public ScriptObject getFunctionPrototype() { 1588 return ScriptFunction.getPrototype(builtinFunction); 1589 } 1590 1591 ScriptObject getArrayPrototype() { 1592 return ScriptFunction.getPrototype(builtinArray); 1593 } 1594 1595 ScriptObject getBooleanPrototype() { 1596 return ScriptFunction.getPrototype(builtinBoolean); 1597 } 1598 1599 ScriptObject getNumberPrototype() { 1600 return ScriptFunction.getPrototype(builtinNumber); 1601 } 1602 1603 ScriptObject getDatePrototype() { 1604 return ScriptFunction.getPrototype(getBuiltinDate()); 1605 } 1606 1607 ScriptObject getRegExpPrototype() { 1608 return ScriptFunction.getPrototype(getBuiltinRegExp()); 1609 } 1610 1611 ScriptObject getStringPrototype() { 1612 return ScriptFunction.getPrototype(builtinString); 1613 } 1614 1615 ScriptObject getErrorPrototype() { 1616 return ScriptFunction.getPrototype(builtinError); 1617 } 1618 1619 ScriptObject getEvalErrorPrototype() { 1620 return ScriptFunction.getPrototype(getBuiltinEvalError()); 1621 } 1622 1623 ScriptObject getRangeErrorPrototype() { 1624 return ScriptFunction.getPrototype(getBuiltinRangeError()); 1625 } 1626 1627 ScriptObject getReferenceErrorPrototype() { 1628 return ScriptFunction.getPrototype(builtinReferenceError); 1629 } 1630 1631 ScriptObject getSyntaxErrorPrototype() { 1632 return ScriptFunction.getPrototype(builtinSyntaxError); 1633 } 1634 1635 ScriptObject getTypeErrorPrototype() { 1636 return ScriptFunction.getPrototype(builtinTypeError); 1637 } 1638 1639 ScriptObject getURIErrorPrototype() { 1640 return ScriptFunction.getPrototype(getBuiltinURIError()); 1641 } 1642 1643 ScriptObject getJavaImporterPrototype() { 1644 return ScriptFunction.getPrototype(getBuiltinJavaImporter()); 1645 } 1646 1647 ScriptObject getJSAdapterPrototype() { 1648 return ScriptFunction.getPrototype(getBuiltinJSAdapter()); 1649 } 1650 1651 private synchronized ScriptFunction getBuiltinArrayBuffer() { 1652 if (this.builtinArrayBuffer == null) { 1653 this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class); 1654 } 1655 return this.builtinArrayBuffer; 1656 } 1657 1658 ScriptObject getArrayBufferPrototype() { 1659 return ScriptFunction.getPrototype(getBuiltinArrayBuffer()); 1660 } 1661 1662 private synchronized ScriptFunction getBuiltinDataView() { 1663 if (this.builtinDataView == null) { 1664 this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class); 1665 } 1666 return this.builtinDataView; 1667 } 1668 1669 ScriptObject getDataViewPrototype() { 1670 return ScriptFunction.getPrototype(getBuiltinDataView()); 1671 } 1672 1673 private synchronized ScriptFunction getBuiltinInt8Array() { 1674 if (this.builtinInt8Array == null) { 1675 this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class); 1676 } 1677 return this.builtinInt8Array; 1678 } 1679 1680 ScriptObject getInt8ArrayPrototype() { 1681 return ScriptFunction.getPrototype(getBuiltinInt8Array()); 1682 } 1683 1684 private synchronized ScriptFunction getBuiltinUint8Array() { 1685 if (this.builtinUint8Array == null) { 1686 this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class); 1687 } 1688 return this.builtinUint8Array; 1689 } 1690 1691 ScriptObject getUint8ArrayPrototype() { 1692 return ScriptFunction.getPrototype(getBuiltinUint8Array()); 1693 } 1694 1695 private synchronized ScriptFunction getBuiltinUint8ClampedArray() { 1696 if (this.builtinUint8ClampedArray == null) { 1697 this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class); 1698 } 1699 return this.builtinUint8ClampedArray; 1700 } 1701 1702 ScriptObject getUint8ClampedArrayPrototype() { 1703 return ScriptFunction.getPrototype(getBuiltinUint8ClampedArray()); 1704 } 1705 1706 private synchronized ScriptFunction getBuiltinInt16Array() { 1707 if (this.builtinInt16Array == null) { 1708 this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class); 1709 } 1710 return this.builtinInt16Array; 1711 } 1712 1713 ScriptObject getInt16ArrayPrototype() { 1714 return ScriptFunction.getPrototype(getBuiltinInt16Array()); 1715 } 1716 1717 private synchronized ScriptFunction getBuiltinUint16Array() { 1718 if (this.builtinUint16Array == null) { 1719 this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class); 1720 } 1721 return this.builtinUint16Array; 1722 } 1723 1724 ScriptObject getUint16ArrayPrototype() { 1725 return ScriptFunction.getPrototype(getBuiltinUint16Array()); 1726 } 1727 1728 private synchronized ScriptFunction getBuiltinInt32Array() { 1729 if (this.builtinInt32Array == null) { 1730 this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class); 1731 } 1732 return this.builtinInt32Array; 1733 } 1734 1735 ScriptObject getInt32ArrayPrototype() { 1736 return ScriptFunction.getPrototype(getBuiltinInt32Array()); 1737 } 1738 1739 private synchronized ScriptFunction getBuiltinUint32Array() { 1740 if (this.builtinUint32Array == null) { 1741 this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class); 1742 } 1743 return this.builtinUint32Array; 1744 } 1745 1746 ScriptObject getUint32ArrayPrototype() { 1747 return ScriptFunction.getPrototype(getBuiltinUint32Array()); 1748 } 1749 1750 private synchronized ScriptFunction getBuiltinFloat32Array() { 1751 if (this.builtinFloat32Array == null) { 1752 this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class); 1753 } 1754 return this.builtinFloat32Array; 1755 } 1756 1757 ScriptObject getFloat32ArrayPrototype() { 1758 return ScriptFunction.getPrototype(getBuiltinFloat32Array()); 1759 } 1760 1761 private synchronized ScriptFunction getBuiltinFloat64Array() { 1762 if (this.builtinFloat64Array == null) { 1763 this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class); 1764 } 1765 return this.builtinFloat64Array; 1766 } 1767 1768 ScriptObject getFloat64ArrayPrototype() { 1769 return ScriptFunction.getPrototype(getBuiltinFloat64Array()); 1770 } 1771 1772 /** 1773 * Return the function that throws TypeError unconditionally. Used as "poison" methods for certain Function properties. 1774 * 1775 * @return the TypeError throwing function 1776 */ 1777 public ScriptFunction getTypeErrorThrower() { 1778 return typeErrorThrower; 1779 } 1780 1781 private synchronized ScriptFunction getBuiltinDate() { 1782 if (this.builtinDate == null) { 1783 this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class); 1784 final ScriptObject dateProto = ScriptFunction.getPrototype(builtinDate); 1785 // initialize default date 1786 this.DEFAULT_DATE = new NativeDate(NaN, dateProto); 1787 } 1788 return this.builtinDate; 1789 } 1790 1791 private synchronized ScriptFunction getBuiltinEvalError() { 1792 if (this.builtinEvalError == null) { 1793 this.builtinEvalError = initErrorSubtype("EvalError", getErrorPrototype()); 1794 } 1795 return this.builtinEvalError; 1796 } 1797 1798 private ScriptFunction getBuiltinFunction() { 1799 return builtinFunction; 1800 } 1801 1802 /** 1803 * Get the switchpoint used to check property changes for Function.prototype.apply 1804 * @return the switchpoint guarding apply (same as guarding call, and everything else in function) 1805 */ 1806 public static SwitchPoint getBuiltinFunctionApplySwitchPoint() { 1807 return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint(); 1808 } 1809 1810 private static boolean isBuiltinFunctionProperty(final String name) { 1811 final Global instance = Global.instance(); 1812 final ScriptFunction builtinFunction = instance.getBuiltinFunction(); 1813 if (builtinFunction == null) { 1814 return false; //conservative for compile-only mode 1815 } 1816 final boolean isBuiltinFunction = instance.function == builtinFunction; 1817 return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin(); 1818 } 1819 1820 /** 1821 * Check if the Function.prototype.apply has not been replaced 1822 * @return true if Function.prototype.apply has been replaced 1823 */ 1824 public static boolean isBuiltinFunctionPrototypeApply() { 1825 return isBuiltinFunctionProperty("apply"); 1826 } 1827 1828 /** 1829 * Check if the Function.prototype.apply has not been replaced 1830 * @return true if Function.prototype.call has been replaced 1831 */ 1832 public static boolean isBuiltinFunctionPrototypeCall() { 1833 return isBuiltinFunctionProperty("call"); 1834 } 1835 1836 private synchronized ScriptFunction getBuiltinJSAdapter() { 1837 if (this.builtinJSAdapter == null) { 1838 this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class); 1839 } 1840 return builtinJSAdapter; 1841 } 1842 1843 private synchronized ScriptObject getBuiltinJSON() { 1844 if (this.builtinJSON == null) { 1845 this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class); 1846 } 1847 return this.builtinJSON; 1848 } 1849 1850 private synchronized ScriptFunction getBuiltinJavaImporter() { 1851 if (this.builtinJavaImporter == null) { 1852 this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class); 1853 } 1854 return this.builtinJavaImporter; 1855 } 1856 1857 private synchronized ScriptObject getBuiltinJavaApi() { 1858 if (this.builtinJavaApi == null) { 1859 this.builtinJavaApi = initConstructor("Java", ScriptObject.class); 1860 } 1861 return this.builtinJavaApi; 1862 } 1863 1864 private synchronized ScriptFunction getBuiltinRangeError() { 1865 if (this.builtinRangeError == null) { 1866 this.builtinRangeError = initErrorSubtype("RangeError", getErrorPrototype()); 1867 } 1868 return builtinRangeError; 1869 } 1870 1871 private synchronized ScriptFunction getBuiltinRegExp() { 1872 if (this.builtinRegExp == null) { 1873 this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class); 1874 final ScriptObject regExpProto = ScriptFunction.getPrototype(builtinRegExp); 1875 // initialize default regexp object 1876 this.DEFAULT_REGEXP = new NativeRegExp("(?:)", "", this, regExpProto); 1877 // RegExp.prototype should behave like a RegExp object. So copy the 1878 // properties. 1879 regExpProto.addBoundProperties(DEFAULT_REGEXP); 1880 } 1881 return builtinRegExp; 1882 } 1883 1884 private synchronized ScriptFunction getBuiltinURIError() { 1885 if (this.builtinURIError == null) { 1886 this.builtinURIError = initErrorSubtype("URIError", getErrorPrototype()); 1887 } 1888 return this.builtinURIError; 1889 } 1890 1891 @Override 1892 public String getClassName() { 1893 return "global"; 1894 } 1895 1896 /** 1897 * Copy function used to clone NativeRegExp objects. 1898 * 1899 * @param regexp a NativeRegExp to clone 1900 * 1901 * @return copy of the given regexp object 1902 */ 1903 public static Object regExpCopy(final Object regexp) { 1904 return new NativeRegExp((NativeRegExp)regexp); 1905 } 1906 1907 /** 1908 * Convert given object to NativeRegExp type. 1909 * 1910 * @param obj object to be converted 1911 * @return NativeRegExp instance 1912 */ 1913 public static NativeRegExp toRegExp(final Object obj) { 1914 if (obj instanceof NativeRegExp) { 1915 return (NativeRegExp)obj; 1916 } 1917 return new NativeRegExp(JSType.toString(obj)); 1918 } 1919 1920 /** 1921 * ECMA 9.9 ToObject implementation 1922 * 1923 * @param obj an item for which to run ToObject 1924 * @return ToObject version of given item 1925 */ 1926 public static Object toObject(final Object obj) { 1927 if (obj == null || obj == UNDEFINED) { 1928 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1929 } 1930 1931 if (obj instanceof ScriptObject) { 1932 return obj; 1933 } 1934 1935 return instance().wrapAsObject(obj); 1936 } 1937 1938 /** 1939 * Allocate a new object array. 1940 * 1941 * @param initial object values. 1942 * @return the new array 1943 */ 1944 public static NativeArray allocate(final Object[] initial) { 1945 ArrayData arrayData = ArrayData.allocate(initial); 1946 1947 for (int index = 0; index < initial.length; index++) { 1948 final Object value = initial[index]; 1949 1950 if (value == ScriptRuntime.EMPTY) { 1951 arrayData = arrayData.delete(index); 1952 } 1953 } 1954 1955 return new NativeArray(arrayData); 1956 } 1957 1958 /** 1959 * Allocate a new number array. 1960 * 1961 * @param initial number values. 1962 * @return the new array 1963 */ 1964 public static NativeArray allocate(final double[] initial) { 1965 return new NativeArray(ArrayData.allocate(initial)); 1966 } 1967 1968 /** 1969 * Allocate a new long array. 1970 * 1971 * @param initial number values. 1972 * @return the new array 1973 */ 1974 public static NativeArray allocate(final long[] initial) { 1975 return new NativeArray(ArrayData.allocate(initial)); 1976 } 1977 1978 /** 1979 * Allocate a new integer array. 1980 * 1981 * @param initial number values. 1982 * @return the new array 1983 */ 1984 public static NativeArray allocate(final int[] initial) { 1985 return new NativeArray(ArrayData.allocate(initial)); 1986 } 1987 1988 /** 1989 * Allocate a new object array for arguments. 1990 * 1991 * @param arguments initial arguments passed. 1992 * @param callee reference to the function that uses arguments object 1993 * @param numParams actual number of declared parameters 1994 * 1995 * @return the new array 1996 */ 1997 public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) { 1998 return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams); 1999 } 2000 2001 /** 2002 * Called from generated to check if given function is the builtin 'eval'. If 2003 * eval is used in a script, a lot of optimizations and assumptions cannot be done. 2004 * 2005 * @param fn function object that is checked 2006 * @return true if fn is the builtin eval 2007 */ 2008 public static boolean isEval(final Object fn) { 2009 return fn == Global.instance().builtinEval; 2010 } 2011 2012 /** 2013 * Called from generated to replace a location property placeholder with the actual location property value. 2014 * 2015 * @param placeholder the value tested for being a placeholder for a location property 2016 * @param locationProperty the actual value for the location property 2017 * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise 2018 */ 2019 public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) { 2020 return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder; 2021 } 2022 2023 /** 2024 * Called from runtime internals to check if the passed value is a location property placeholder. 2025 * @param placeholder the value tested for being a placeholder for a location property 2026 * @return true if the value is a placeholder, false otherwise. 2027 */ 2028 public static boolean isLocationPropertyPlaceholder(final Object placeholder) { 2029 return placeholder == LAZY_SENTINEL; 2030 } 2031 2032 /** 2033 * Create a new RegExp object. 2034 * 2035 * @param expression Regular expression. 2036 * @param options Search options. 2037 * 2038 * @return New RegExp object. 2039 */ 2040 public static Object newRegExp(final String expression, final String options) { 2041 if (options == null) { 2042 return new NativeRegExp(expression); 2043 } 2044 return new NativeRegExp(expression, options); 2045 } 2046 2047 /** 2048 * Get the object prototype 2049 * 2050 * @return the object prototype 2051 */ 2052 public static ScriptObject objectPrototype() { 2053 return Global.instance().getObjectPrototype(); 2054 } 2055 2056 /** 2057 * Create a new empty object instance. 2058 * 2059 * @return New empty object. 2060 */ 2061 public static ScriptObject newEmptyInstance() { 2062 return Global.instance().newObject(); 2063 } 2064 2065 /** 2066 * Check if a given object is a ScriptObject, raises an exception if this is 2067 * not the case 2068 * 2069 * @param obj and object to check 2070 * @return the script object 2071 */ 2072 public static ScriptObject checkObject(final Object obj) { 2073 if (!(obj instanceof ScriptObject)) { 2074 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 2075 } 2076 return (ScriptObject)obj; 2077 } 2078 2079 /** 2080 * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception 2081 * if this object is null or undefined. 2082 * 2083 * @param obj an object to check 2084 */ 2085 public static void checkObjectCoercible(final Object obj) { 2086 if (obj == null || obj == UNDEFINED) { 2087 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 2088 } 2089 } 2090 2091 /** 2092 * Return the ES6 global scope for lexically declared bindings. 2093 * @return the ES6 lexical global scope. 2094 */ 2095 public final ScriptObject getLexicalScope() { 2096 assert context.getEnv()._es6; 2097 return lexicalScope; 2098 } 2099 2100 @Override 2101 public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) { 2102 PropertyMap ownMap = getMap(); 2103 LexicalScope lexScope = null; 2104 PropertyMap lexicalMap = null; 2105 boolean hasLexicalDefinitions = false; 2106 2107 if (context.getEnv()._es6) { 2108 lexScope = (LexicalScope) getLexicalScope(); 2109 lexicalMap = lexScope.getMap(); 2110 2111 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2112 if (property.isLexicalBinding()) { 2113 hasLexicalDefinitions = true; 2114 } 2115 // ES6 15.1.8 steps 6. and 7. 2116 final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey()); 2117 if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) { 2118 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); 2119 } 2120 final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey()); 2121 if (lexicalProperty != null && !property.isConfigurable()) { 2122 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); 2123 } 2124 } 2125 } 2126 2127 final boolean extensible = isExtensible(); 2128 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2129 if (property.isLexicalBinding()) { 2130 assert lexScope != null; 2131 lexicalMap = lexScope.addBoundProperty(lexicalMap, source, property, true); 2132 2133 if (ownMap.findProperty(property.getKey()) != null) { 2134 // If property exists in the global object invalidate any global constant call sites. 2135 invalidateGlobalConstant(property.getKey()); 2136 } 2137 } else { 2138 ownMap = addBoundProperty(ownMap, source, property, extensible); 2139 } 2140 } 2141 2142 setMap(ownMap); 2143 2144 if (hasLexicalDefinitions) { 2145 assert lexScope != null; 2146 lexScope.setMap(lexicalMap); 2147 invalidateLexicalSwitchPoint(); 2148 } 2149 } 2150 2151 @Override 2152 public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { 2153 final String name = NashornCallSiteDescriptor.getOperand(desc); 2154 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 2155 2156 if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { 2157 if (lexicalScope.hasOwnProperty(name)) { 2158 return lexicalScope.findGetMethod(desc, request, operation); 2159 } 2160 } 2161 2162 final GuardedInvocation invocation = super.findGetMethod(desc, request, operation); 2163 2164 // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, 2165 // because those are invalidated per-key in the addBoundProperties method above. 2166 // We therefore check if the invocation does already have a switchpoint and the property is non-inherited, 2167 // assuming this only applies to global constants. If other non-inherited properties will 2168 // start using switchpoints some time in the future we'll have to revisit this. 2169 if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { 2170 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 2171 } 2172 2173 return invocation; 2174 } 2175 2176 @Override 2177 protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) { 2178 if (lexicalScope != null && start != this && start.isScope()) { 2179 final FindProperty find = lexicalScope.findProperty(key, false); 2180 if (find != null) { 2181 return find; 2182 } 2183 } 2184 return super.findProperty(key, deep, start); 2185 } 2186 2187 @Override 2188 public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 2189 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 2190 2191 if (lexicalScope != null && isScope) { 2192 final String name = NashornCallSiteDescriptor.getOperand(desc); 2193 if (lexicalScope.hasOwnProperty(name)) { 2194 return lexicalScope.findSetMethod(desc, request); 2195 } 2196 } 2197 2198 final GuardedInvocation invocation = super.findSetMethod(desc, request); 2199 2200 if (isScope && context.getEnv()._es6) { 2201 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 2202 } 2203 2204 return invocation; 2205 } 2206 2207 /** 2208 * Adds jjs shell interactive mode builtin functions to global scope. 2209 */ 2210 public void addShellBuiltins() { 2211 Object value = ScriptFunction.createBuiltin("input", ShellFunctions.INPUT); 2212 addOwnProperty("input", Attribute.NOT_ENUMERABLE, value); 2213 2214 value = ScriptFunction.createBuiltin("evalinput", ShellFunctions.EVALINPUT); 2215 addOwnProperty("evalinput", Attribute.NOT_ENUMERABLE, value); 2216 } 2217 2218 private synchronized SwitchPoint getLexicalScopeSwitchPoint() { 2219 SwitchPoint switchPoint = lexicalScopeSwitchPoint; 2220 if (switchPoint == null || switchPoint.hasBeenInvalidated()) { 2221 switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); 2222 } 2223 return switchPoint; 2224 } 2225 2226 private synchronized void invalidateLexicalSwitchPoint() { 2227 if (lexicalScopeSwitchPoint != null) { 2228 context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); 2229 SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); 2230 } 2231 } 2232 2233 2234 @SuppressWarnings("unused") 2235 private static Object lexicalScopeFilter(final Object self) { 2236 if (self instanceof Global) { 2237 return ((Global) self).getLexicalScope(); 2238 } 2239 return self; 2240 } 2241 2242 private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) { 2243 final T func = initConstructor(name, clazz); 2244 tagBuiltinProperties(name, func); 2245 return func; 2246 } 2247 2248 private void init(final ScriptEngine eng) { 2249 assert Context.getGlobal() == this : "this global is not set as current"; 2250 2251 final ScriptEnvironment env = getContext().getEnv(); 2252 2253 // initialize Function and Object constructor 2254 initFunctionAndObject(); 2255 2256 // Now fix Global's own proto. 2257 this.setInitialProto(getObjectPrototype()); 2258 2259 // initialize global function properties 2260 this.eval = this.builtinEval = ScriptFunction.createBuiltin("eval", EVAL); 2261 2262 this.parseInt = ScriptFunction.createBuiltin("parseInt", GlobalFunctions.PARSEINT, 2263 new Specialization[] { 2264 new Specialization(GlobalFunctions.PARSEINT_Z), 2265 new Specialization(GlobalFunctions.PARSEINT_I), 2266 new Specialization(GlobalFunctions.PARSEINT_J), 2267 new Specialization(GlobalFunctions.PARSEINT_OI), 2268 new Specialization(GlobalFunctions.PARSEINT_O) }); 2269 this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT); 2270 this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN, 2271 new Specialization[] { 2272 new Specialization(GlobalFunctions.IS_NAN_I), 2273 new Specialization(GlobalFunctions.IS_NAN_J), 2274 new Specialization(GlobalFunctions.IS_NAN_D) }); 2275 this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT); 2276 this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN); 2277 this.isFinite = ScriptFunction.createBuiltin("isFinite", GlobalFunctions.IS_FINITE); 2278 this.encodeURI = ScriptFunction.createBuiltin("encodeURI", GlobalFunctions.ENCODE_URI); 2279 this.encodeURIComponent = ScriptFunction.createBuiltin("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT); 2280 this.decodeURI = ScriptFunction.createBuiltin("decodeURI", GlobalFunctions.DECODE_URI); 2281 this.decodeURIComponent = ScriptFunction.createBuiltin("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); 2282 this.escape = ScriptFunction.createBuiltin("escape", GlobalFunctions.ESCAPE); 2283 this.unescape = ScriptFunction.createBuiltin("unescape", GlobalFunctions.UNESCAPE); 2284 this.print = ScriptFunction.createBuiltin("print", env._print_no_newline ? PRINT : PRINTLN); 2285 this.load = ScriptFunction.createBuiltin("load", LOAD); 2286 this.loadWithNewGlobal = ScriptFunction.createBuiltin("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); 2287 this.exit = ScriptFunction.createBuiltin("exit", EXIT); 2288 this.quit = ScriptFunction.createBuiltin("quit", EXIT); 2289 2290 // built-in constructors 2291 this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class); 2292 this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class); 2293 this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class); 2294 this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class); 2295 this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class); 2296 2297 // initialize String.prototype.length to 0 2298 // add String.prototype.length 2299 final ScriptObject stringPrototype = getStringPrototype(); 2300 stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0); 2301 2302 // set isArray flag on Array.prototype 2303 final ScriptObject arrayPrototype = getArrayPrototype(); 2304 arrayPrototype.setIsArray(); 2305 2306 // Error stuff 2307 initErrorObjects(); 2308 2309 // java access 2310 if (! env._no_java) { 2311 this.javaApi = LAZY_SENTINEL; 2312 this.javaImporter = LAZY_SENTINEL; 2313 initJavaAccess(); 2314 } 2315 2316 if (! env._no_typed_arrays) { 2317 this.arrayBuffer = LAZY_SENTINEL; 2318 this.dataView = LAZY_SENTINEL; 2319 this.int8Array = LAZY_SENTINEL; 2320 this.uint8Array = LAZY_SENTINEL; 2321 this.uint8ClampedArray = LAZY_SENTINEL; 2322 this.int16Array = LAZY_SENTINEL; 2323 this.uint16Array = LAZY_SENTINEL; 2324 this.int32Array = LAZY_SENTINEL; 2325 this.uint32Array = LAZY_SENTINEL; 2326 this.float32Array = LAZY_SENTINEL; 2327 this.float64Array = LAZY_SENTINEL; 2328 } 2329 2330 if (env._scripting) { 2331 initScripting(env); 2332 } 2333 2334 if (Context.DEBUG) { 2335 boolean debugOkay; 2336 final SecurityManager sm = System.getSecurityManager(); 2337 if (sm != null) { 2338 try { 2339 sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE)); 2340 debugOkay = true; 2341 } catch (final SecurityException ignored) { 2342 // if no permission, don't initialize Debug object 2343 debugOkay = false; 2344 } 2345 2346 } else { 2347 debugOkay = true; 2348 } 2349 2350 if (debugOkay) { 2351 initDebug(); 2352 } 2353 } 2354 2355 copyBuiltins(); 2356 2357 // expose script (command line) arguments as "arguments" property of global 2358 arguments = wrapAsObject(env.getArguments().toArray()); 2359 if (env._scripting) { 2360 // synonym for "arguments" in scripting mode 2361 addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); 2362 } 2363 2364 if (eng != null) { 2365 // default file name 2366 addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); 2367 // __noSuchProperty__ hook for ScriptContext search of missing variables 2368 final ScriptFunction noSuchProp = ScriptFunction.createStrictBuiltin(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY); 2369 addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp); 2370 } 2371 } 2372 2373 private void initErrorObjects() { 2374 // Error objects 2375 this.builtinError = initConstructor("Error", ScriptFunction.class); 2376 final ScriptObject errorProto = getErrorPrototype(); 2377 2378 // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName 2379 final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", NativeError.GET_STACK); 2380 final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", NativeError.SET_STACK); 2381 errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); 2382 final ScriptFunction getLineNumber = ScriptFunction.createBuiltin("getLineNumber", NativeError.GET_LINENUMBER); 2383 final ScriptFunction setLineNumber = ScriptFunction.createBuiltin("setLineNumber", NativeError.SET_LINENUMBER); 2384 errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber); 2385 final ScriptFunction getColumnNumber = ScriptFunction.createBuiltin("getColumnNumber", NativeError.GET_COLUMNNUMBER); 2386 final ScriptFunction setColumnNumber = ScriptFunction.createBuiltin("setColumnNumber", NativeError.SET_COLUMNNUMBER); 2387 errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber); 2388 final ScriptFunction getFileName = ScriptFunction.createBuiltin("getFileName", NativeError.GET_FILENAME); 2389 final ScriptFunction setFileName = ScriptFunction.createBuiltin("setFileName", NativeError.SET_FILENAME); 2390 errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName); 2391 2392 // ECMA 15.11.4.2 Error.prototype.name 2393 // Error.prototype.name = "Error"; 2394 errorProto.set(NativeError.NAME, "Error", 0); 2395 // ECMA 15.11.4.3 Error.prototype.message 2396 // Error.prototype.message = ""; 2397 errorProto.set(NativeError.MESSAGE, "", 0); 2398 2399 tagBuiltinProperties("Error", builtinError); 2400 2401 this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto); 2402 this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto); 2403 this.builtinTypeError = initErrorSubtype("TypeError", errorProto); 2404 } 2405 2406 private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { 2407 final ScriptFunction cons = initConstructor(name, ScriptFunction.class); 2408 final ScriptObject prototype = ScriptFunction.getPrototype(cons); 2409 prototype.set(NativeError.NAME, name, 0); 2410 prototype.set(NativeError.MESSAGE, "", 0); 2411 prototype.setInitialProto(errorProto); 2412 tagBuiltinProperties(name, cons); 2413 return cons; 2414 } 2415 2416 private void initJavaAccess() { 2417 final ScriptObject objectProto = getObjectPrototype(); 2418 this.builtinPackages = new NativeJavaPackage("", objectProto); 2419 this.builtinCom = new NativeJavaPackage("com", objectProto); 2420 this.builtinEdu = new NativeJavaPackage("edu", objectProto); 2421 this.builtinJava = new NativeJavaPackage("java", objectProto); 2422 this.builtinJavafx = new NativeJavaPackage("javafx", objectProto); 2423 this.builtinJavax = new NativeJavaPackage("javax", objectProto); 2424 this.builtinOrg = new NativeJavaPackage("org", objectProto); 2425 } 2426 2427 private void initScripting(final ScriptEnvironment scriptEnv) { 2428 ScriptObject value; 2429 value = ScriptFunction.createBuiltin("readLine", ScriptingFunctions.READLINE); 2430 addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); 2431 2432 value = ScriptFunction.createBuiltin("readFully", ScriptingFunctions.READFULLY); 2433 addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); 2434 2435 final String execName = ScriptingFunctions.EXEC_NAME; 2436 value = ScriptFunction.createBuiltin(execName, ScriptingFunctions.EXEC); 2437 value.addOwnProperty(ScriptingFunctions.THROW_ON_ERROR_NAME, Attribute.NOT_ENUMERABLE, false); 2438 2439 addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); 2440 2441 // Nashorn extension: global.echo (scripting-mode-only) 2442 // alias for "print" 2443 value = (ScriptObject)get("print"); 2444 addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); 2445 2446 // Nashorn extension: global.$OPTIONS (scripting-mode-only) 2447 final ScriptObject options = newObject(); 2448 copyOptions(options, scriptEnv); 2449 addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options); 2450 2451 // Nashorn extension: global.$ENV (scripting-mode-only) 2452 if (System.getSecurityManager() == null) { 2453 // do not fill $ENV if we have a security manager around 2454 // Retrieve current state of ENV variables. 2455 final ScriptObject env = newObject(); 2456 env.putAll(System.getenv(), scriptEnv._strict); 2457 2458 // Some platforms, e.g., Windows, do not define the PWD environment 2459 // variable, so that the $ENV.PWD property needs to be explicitly 2460 // set. 2461 if (!env.containsKey(ScriptingFunctions.PWD_NAME)) { 2462 env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict); 2463 } 2464 2465 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); 2466 } else { 2467 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2468 } 2469 2470 // add other special properties for exec support 2471 addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2472 addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2473 addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2474 } 2475 2476 private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { 2477 for (final Field f : scriptEnv.getClass().getFields()) { 2478 try { 2479 options.set(f.getName(), f.get(scriptEnv), 0); 2480 } catch (final IllegalArgumentException | IllegalAccessException exp) { 2481 throw new RuntimeException(exp); 2482 } 2483 } 2484 } 2485 2486 private void copyBuiltins() { 2487 this.array = this.builtinArray; 2488 this._boolean = this.builtinBoolean; 2489 this.error = this.builtinError; 2490 this.function = this.builtinFunction; 2491 this.com = this.builtinCom; 2492 this.edu = this.builtinEdu; 2493 this.java = this.builtinJava; 2494 this.javafx = this.builtinJavafx; 2495 this.javax = this.builtinJavax; 2496 this.org = this.builtinOrg; 2497 this.math = this.builtinMath; 2498 this.number = this.builtinNumber; 2499 this.object = this.builtinObject; 2500 this.packages = this.builtinPackages; 2501 this.referenceError = this.builtinReferenceError; 2502 this.string = this.builtinString; 2503 this.syntaxError = this.builtinSyntaxError; 2504 this.typeError = this.builtinTypeError; 2505 } 2506 2507 private void initDebug() { 2508 this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class)); 2509 } 2510 2511 private Object printImpl(final boolean newLine, final Object... objects) { 2512 final ScriptContext sc = currentContext(); 2513 @SuppressWarnings("resource") 2514 final PrintWriter out = sc != null? new PrintWriter(sc.getWriter()) : getContext().getEnv().getOut(); 2515 final StringBuilder sb = new StringBuilder(); 2516 2517 for (final Object obj : objects) { 2518 if (sb.length() != 0) { 2519 sb.append(' '); 2520 } 2521 2522 sb.append(JSType.toString(obj)); 2523 } 2524 2525 // Print all at once to ensure thread friendly result. 2526 if (newLine) { 2527 out.println(sb.toString()); 2528 } else { 2529 out.print(sb.toString()); 2530 } 2531 2532 out.flush(); 2533 2534 return UNDEFINED; 2535 } 2536 2537 private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) { 2538 try { 2539 // Assuming class name pattern for built-in JS constructors. 2540 final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects."); 2541 2542 sb.append("Native"); 2543 sb.append(name); 2544 sb.append("$Constructor"); 2545 2546 final Class<?> funcClass = Class.forName(sb.toString()); 2547 final T res = clazz.cast(funcClass.newInstance()); 2548 2549 if (res instanceof ScriptFunction) { 2550 // All global constructor prototypes are not-writable, 2551 // not-enumerable and not-configurable. 2552 final ScriptFunction func = (ScriptFunction)res; 2553 func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT); 2554 } 2555 2556 if (res.getProto() == null) { 2557 res.setInitialProto(getObjectPrototype()); 2558 } 2559 2560 res.setIsBuiltin(); 2561 2562 return res; 2563 } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { 2564 throw new RuntimeException(e); 2565 } 2566 } 2567 2568 private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) { 2569 final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>(); 2570 2571 list.addAll(Arrays.asList(func.getMap().getProperties())); 2572 2573 if (func instanceof ScriptFunction) { 2574 final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func); 2575 if (proto != null) { 2576 list.addAll(Arrays.asList(proto.getMap().getProperties())); 2577 } 2578 } 2579 2580 final jdk.nashorn.internal.runtime.Property prop = getProperty(name); 2581 if (prop != null) { 2582 list.add(prop); 2583 } 2584 2585 return list; 2586 } 2587 2588 /** 2589 * Given a builtin object, traverse its properties recursively and associate them with a name that 2590 * will be a key to their invalidation switchpoint. 2591 * @param name name for key 2592 * @param func builtin script object 2593 */ 2594 private void tagBuiltinProperties(final String name, final ScriptObject func) { 2595 SwitchPoint sp = context.getBuiltinSwitchPoint(name); 2596 if (sp == null) { 2597 sp = context.newBuiltinSwitchPoint(name); 2598 } 2599 2600 //get all builtin properties in this builtin object and register switchpoints keyed on the propery name, 2601 //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc 2602 for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) { 2603 prop.setBuiltinSwitchPoint(sp); 2604 } 2605 } 2606 2607 // Function and Object constructors are inter-dependent. Also, 2608 // Function.prototype 2609 // functions are not properly initialized. We fix the references here. 2610 // NOTE: be careful if you want to re-order the operations here. You may 2611 // have 2612 // to play with object references carefully!! 2613 private void initFunctionAndObject() { 2614 // First-n-foremost is Function 2615 2616 this.builtinFunction = initConstructor("Function", ScriptFunction.class); 2617 2618 // create global anonymous function 2619 final ScriptFunction anon = ScriptFunction.createAnonymous(); 2620 // need to copy over members of Function.prototype to anon function 2621 anon.addBoundProperties(getFunctionPrototype()); 2622 2623 // Function.prototype === Object.getPrototypeOf(Function) === 2624 // <anon-function> 2625 builtinFunction.setInitialProto(anon); 2626 builtinFunction.setPrototype(anon); 2627 anon.set("constructor", builtinFunction, 0); 2628 anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); 2629 2630 // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 2631 this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER); 2632 typeErrorThrower.preventExtensions(); 2633 2634 // now initialize Object 2635 this.builtinObject = initConstructor("Object", ScriptFunction.class); 2636 final ScriptObject ObjectPrototype = getObjectPrototype(); 2637 // Object.getPrototypeOf(Function.prototype) === Object.prototype 2638 anon.setInitialProto(ObjectPrototype); 2639 2640 // ES6 draft compliant __proto__ property of Object.prototype 2641 // accessors on Object.prototype for "__proto__" 2642 final ScriptFunction getProto = ScriptFunction.createBuiltin("getProto", NativeObject.GET__PROTO__); 2643 final ScriptFunction setProto = ScriptFunction.createBuiltin("setProto", NativeObject.SET__PROTO__); 2644 ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); 2645 2646 // Function valued properties of Function.prototype were not properly 2647 // initialized. Because, these were created before global.function and 2648 // global.object were not initialized. 2649 jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties(); 2650 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2651 final Object key = property.getKey(); 2652 final Object value = builtinFunction.get(key); 2653 2654 if (value instanceof ScriptFunction && value != anon) { 2655 final ScriptFunction func = (ScriptFunction)value; 2656 func.setInitialProto(getFunctionPrototype()); 2657 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2658 if (prototype != null) { 2659 prototype.setInitialProto(ObjectPrototype); 2660 } 2661 } 2662 } 2663 2664 // For function valued properties of Object and Object.prototype, make 2665 // sure prototype's proto chain ends with Object.prototype 2666 for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) { 2667 final Object key = property.getKey(); 2668 final Object value = builtinObject.get(key); 2669 2670 if (value instanceof ScriptFunction) { 2671 final ScriptFunction func = (ScriptFunction)value; 2672 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2673 if (prototype != null) { 2674 prototype.setInitialProto(ObjectPrototype); 2675 } 2676 } 2677 } 2678 2679 properties = getObjectPrototype().getMap().getProperties(); 2680 2681 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2682 final Object key = property.getKey(); 2683 if (key.equals("constructor")) { 2684 continue; 2685 } 2686 2687 final Object value = ObjectPrototype.get(key); 2688 if (value instanceof ScriptFunction) { 2689 final ScriptFunction func = (ScriptFunction)value; 2690 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2691 if (prototype != null) { 2692 prototype.setInitialProto(ObjectPrototype); 2693 } 2694 } 2695 } 2696 2697 tagBuiltinProperties("Object", builtinObject); 2698 tagBuiltinProperties("Function", builtinFunction); 2699 tagBuiltinProperties("Function", anon); 2700 } 2701 2702 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) { 2703 return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types)); 2704 } 2705 2706 RegExpResult getLastRegExpResult() { 2707 return lastRegExpResult; 2708 } 2709 2710 void setLastRegExpResult(final RegExpResult regExpResult) { 2711 this.lastRegExpResult = regExpResult; 2712 } 2713 2714 @Override 2715 protected boolean isGlobal() { 2716 return true; 2717 } 2718 2719 /** 2720 * A class representing the ES6 global lexical scope. 2721 */ 2722 private static class LexicalScope extends ScriptObject { 2723 2724 LexicalScope(final Global global) { 2725 super(global, PropertyMap.newMap()); 2726 } 2727 2728 @Override 2729 protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { 2730 return filterInvocation(super.findGetMethod(desc, request, operation)); 2731 } 2732 2733 @Override 2734 protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 2735 return filterInvocation(super.findSetMethod(desc, request)); 2736 } 2737 2738 @Override 2739 protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property, final boolean extensible) { 2740 // We override this method just to make it callable by Global 2741 return super.addBoundProperty(propMap, source, property, extensible); 2742 } 2743 2744 private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { 2745 final MethodType type = invocation.getInvocation().type(); 2746 return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); 2747 } 2748 } 2749 2750} 2751