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