Global.java revision 1621:1d7aaa18e5e5
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 } else if (self instanceof Symbol) { 1137 return NativeSymbol.lookupPrimitive(request, self); 1138 } 1139 throw new IllegalArgumentException("Unsupported primitive: " + self); 1140 } 1141 1142 /** 1143 * Returns a method handle that creates a wrapper object for a JS primitive value. 1144 * 1145 * @param self receiver object 1146 * @return method handle to create wrapper objects for primitive receiver 1147 */ 1148 public static MethodHandle getPrimitiveWrapFilter(final Object self) { 1149 if (isString(self)) { 1150 return NativeString.WRAPFILTER; 1151 } else if (self instanceof Number) { 1152 return NativeNumber.WRAPFILTER; 1153 } else if (self instanceof Boolean) { 1154 return NativeBoolean.WRAPFILTER; 1155 } 1156 throw new IllegalArgumentException("Unsupported primitive: " + self); 1157 } 1158 1159 1160 /** 1161 * Create a new empty script object 1162 * 1163 * @return the new ScriptObject 1164 */ 1165 public ScriptObject newObject() { 1166 return useDualFields() ? new JD(getObjectPrototype()) : new JO(getObjectPrototype()); 1167 } 1168 1169 /** 1170 * Default value of given type 1171 * 1172 * @param sobj script object 1173 * @param typeHint type hint 1174 * 1175 * @return default value 1176 */ 1177 public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) { 1178 // When the [[DefaultValue]] internal method of O is called with no hint, 1179 // then it behaves as if the hint were Number, unless O is a Date object 1180 // in which case it behaves as if the hint were String. 1181 Class<?> hint = typeHint; 1182 if (hint == null) { 1183 hint = Number.class; 1184 } 1185 1186 try { 1187 if (hint == String.class) { 1188 1189 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 1190 1191 if (Bootstrap.isCallable(toString)) { 1192 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 1193 if (JSType.isPrimitive(value)) { 1194 return value; 1195 } 1196 } 1197 1198 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 1199 if (Bootstrap.isCallable(valueOf)) { 1200 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 1201 if (JSType.isPrimitive(value)) { 1202 return value; 1203 } 1204 } 1205 throw typeError(this, "cannot.get.default.string"); 1206 } 1207 1208 if (hint == Number.class) { 1209 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 1210 if (Bootstrap.isCallable(valueOf)) { 1211 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 1212 if (JSType.isPrimitive(value)) { 1213 return value; 1214 } 1215 } 1216 1217 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 1218 if (Bootstrap.isCallable(toString)) { 1219 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 1220 if (JSType.isPrimitive(value)) { 1221 return value; 1222 } 1223 } 1224 1225 throw typeError(this, "cannot.get.default.number"); 1226 } 1227 } catch (final RuntimeException | Error e) { 1228 throw e; 1229 } catch (final Throwable t) { 1230 throw new RuntimeException(t); 1231 } 1232 1233 return UNDEFINED; 1234 } 1235 1236 /** 1237 * Is the given ScriptObject an ECMAScript Error object? 1238 * 1239 * @param sobj the object being checked 1240 * @return true if sobj is an Error object 1241 */ 1242 public boolean isError(final ScriptObject sobj) { 1243 final ScriptObject errorProto = getErrorPrototype(); 1244 ScriptObject proto = sobj.getProto(); 1245 while (proto != null) { 1246 if (proto == errorProto) { 1247 return true; 1248 } 1249 proto = proto.getProto(); 1250 } 1251 return false; 1252 } 1253 1254 /** 1255 * Create a new ECMAScript Error object. 1256 * 1257 * @param msg error message 1258 * @return newly created Error object 1259 */ 1260 public ScriptObject newError(final String msg) { 1261 return new NativeError(msg, this); 1262 } 1263 1264 /** 1265 * Create a new ECMAScript EvalError object. 1266 * 1267 * @param msg error message 1268 * @return newly created EvalError object 1269 */ 1270 public ScriptObject newEvalError(final String msg) { 1271 return new NativeEvalError(msg, this); 1272 } 1273 1274 /** 1275 * Create a new ECMAScript RangeError object. 1276 * 1277 * @param msg error message 1278 * @return newly created RangeError object 1279 */ 1280 public ScriptObject newRangeError(final String msg) { 1281 return new NativeRangeError(msg, this); 1282 } 1283 1284 /** 1285 * Create a new ECMAScript ReferenceError object. 1286 * 1287 * @param msg error message 1288 * @return newly created ReferenceError object 1289 */ 1290 public ScriptObject newReferenceError(final String msg) { 1291 return new NativeReferenceError(msg, this); 1292 } 1293 1294 /** 1295 * Create a new ECMAScript SyntaxError object. 1296 * 1297 * @param msg error message 1298 * @return newly created SyntaxError object 1299 */ 1300 public ScriptObject newSyntaxError(final String msg) { 1301 return new NativeSyntaxError(msg, this); 1302 } 1303 1304 /** 1305 * Create a new ECMAScript TypeError object. 1306 * 1307 * @param msg error message 1308 * @return newly created TypeError object 1309 */ 1310 public ScriptObject newTypeError(final String msg) { 1311 return new NativeTypeError(msg, this); 1312 } 1313 1314 /** 1315 * Create a new ECMAScript URIError object. 1316 * 1317 * @param msg error message 1318 * @return newly created URIError object 1319 */ 1320 public ScriptObject newURIError(final String msg) { 1321 return new NativeURIError(msg, this); 1322 } 1323 1324 /** 1325 * Create a new ECMAScript GenericDescriptor object. 1326 * 1327 * @param configurable is the property configurable? 1328 * @param enumerable is the property enumerable? 1329 * @return newly created GenericDescriptor object 1330 */ 1331 public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) { 1332 return new GenericPropertyDescriptor(configurable, enumerable, this); 1333 } 1334 1335 /** 1336 * Create a new ECMAScript DatePropertyDescriptor object. 1337 * 1338 * @param value of the data property 1339 * @param configurable is the property configurable? 1340 * @param enumerable is the property enumerable? 1341 * @param writable is the property writable? 1342 * @return newly created DataPropertyDescriptor object 1343 */ 1344 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { 1345 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this); 1346 } 1347 1348 /** 1349 * Create a new ECMAScript AccessorPropertyDescriptor object. 1350 * 1351 * @param get getter function of the user accessor property 1352 * @param set setter function of the user accessor property 1353 * @param configurable is the property configurable? 1354 * @param enumerable is the property enumerable? 1355 * @return newly created AccessorPropertyDescriptor object 1356 */ 1357 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { 1358 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this); 1359 1360 if (get == null) { 1361 desc.delete(PropertyDescriptor.GET, false); 1362 } 1363 1364 if (set == null) { 1365 desc.delete(PropertyDescriptor.SET, false); 1366 } 1367 1368 return desc; 1369 } 1370 1371 private <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) { 1372 final T obj = map.get(key); 1373 if (obj != null) { 1374 return obj; 1375 } 1376 1377 final Global oldGlobal = Context.getGlobal(); 1378 final boolean differentGlobal = oldGlobal != this; 1379 try { 1380 if (differentGlobal) { 1381 Context.setGlobal(this); 1382 } 1383 final T newObj = creator.call(); 1384 final T existingObj = map.putIfAbsent(key, newObj); 1385 return existingObj != null ? existingObj : newObj; 1386 } catch (final Exception exp) { 1387 throw new RuntimeException(exp); 1388 } finally { 1389 if (differentGlobal) { 1390 Context.setGlobal(oldGlobal); 1391 } 1392 } 1393 } 1394 1395 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>(); 1396 1397 1398 /** 1399 * Get cached InvokeByName object for the given key 1400 * @param key key to be associated with InvokeByName object 1401 * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) 1402 * @return InvokeByName object associated with the key. 1403 */ 1404 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) { 1405 return getLazilyCreatedValue(key, creator, namedInvokers); 1406 } 1407 1408 private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>(); 1409 1410 /** 1411 * Get cached dynamic method handle for the given key 1412 * @param key key to be associated with dynamic method handle 1413 * @param creator if method handle is absent 'creator' is called to make one (lazy init) 1414 * @return dynamic method handle associated with the key. 1415 */ 1416 public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) { 1417 return getLazilyCreatedValue(key, creator, dynamicInvokers); 1418 } 1419 1420 /** 1421 * Hook to search missing variables in ScriptContext if available 1422 * @param self used to detect if scope call or not (this function is 'strict') 1423 * @param name name of the variable missing 1424 * @return value of the missing variable or undefined (or TypeError for scope search) 1425 */ 1426 public static Object __noSuchProperty__(final Object self, final Object name) { 1427 final Global global = Global.instance(); 1428 final ScriptContext sctxt = global.currentContext(); 1429 final String nameStr = name.toString(); 1430 1431 if (sctxt != null) { 1432 final int scope = sctxt.getAttributesScope(nameStr); 1433 if (scope != -1) { 1434 return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global); 1435 } 1436 } 1437 1438 switch (nameStr) { 1439 case "context": 1440 return sctxt; 1441 case "engine": 1442 return global.engine; 1443 default: 1444 break; 1445 } 1446 1447 if (self == UNDEFINED) { 1448 // scope access and so throw ReferenceError 1449 throw referenceError(global, "not.defined", nameStr); 1450 } 1451 1452 return UNDEFINED; 1453 } 1454 1455 /** 1456 * This is the eval used when 'indirect' eval call is made. 1457 * 1458 * var global = this; 1459 * global.eval("print('hello')"); 1460 * 1461 * @param self eval scope 1462 * @param str eval string 1463 * 1464 * @return the result of eval 1465 */ 1466 public static Object eval(final Object self, final Object str) { 1467 return directEval(self, str, Global.instanceFrom(self), UNDEFINED, false); 1468 } 1469 1470 /** 1471 * Direct eval 1472 * 1473 * @param self The scope of eval passed as 'self' 1474 * @param str Evaluated code 1475 * @param callThis "this" to be passed to the evaluated code 1476 * @param location location of the eval call 1477 * @param strict is eval called from a strict mode code? 1478 * 1479 * @return the return value of the eval 1480 * 1481 * This is directly invoked from generated when eval(code) is called in user code 1482 */ 1483 public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) { 1484 if (!isString(str)) { 1485 return str; 1486 } 1487 final Global global = Global.instanceFrom(self); 1488 final ScriptObject scope = self instanceof ScriptObject && ((ScriptObject)self).isScope() ? (ScriptObject)self : global; 1489 1490 return global.getContext().eval(scope, str.toString(), callThis, location, strict, true); 1491 } 1492 1493 /** 1494 * Global print implementation - Nashorn extension 1495 * 1496 * @param self scope 1497 * @param objects arguments to print 1498 * 1499 * @return result of print (undefined) 1500 */ 1501 public static Object print(final Object self, final Object... objects) { 1502 return Global.instanceFrom(self).printImpl(false, objects); 1503 } 1504 1505 /** 1506 * Global println implementation - Nashorn extension 1507 * 1508 * @param self scope 1509 * @param objects arguments to print 1510 * 1511 * @return result of println (undefined) 1512 */ 1513 public static Object println(final Object self, final Object... objects) { 1514 return Global.instanceFrom(self).printImpl(true, objects); 1515 } 1516 1517 /** 1518 * Global load implementation - Nashorn extension. 1519 * 1520 * <p> 1521 * load builtin loads the given script. Script source can be a URL or a File 1522 * or a script object with name and script properties. Evaluated code gets 1523 * global object "this" and uses global object as scope for evaluation. 1524 * </p> 1525 * <p> 1526 * If self is undefined or null or global, then global object is used 1527 * as scope as well as "this" for the evaluated code. If self is any other 1528 * object, then it is indirect load call. With indirect load call, the 1529 * properties of scope are available to evaluated script as variables. Also, 1530 * global scope properties are accessible. Any var, function definition in 1531 * evaluated script goes into an object that is not accessible to user scripts. 1532 * </p> 1533 * Thus the indirect load call is equivalent to the following: 1534 * <pre> 1535 * <code> 1536 * (function (scope, source) { 1537 * with(scope) { 1538 * eval(<script_from_source>); 1539 * } 1540 * })(self, source); 1541 * </code> 1542 * </pre> 1543 * 1544 * @param self scope to use for the script evaluation 1545 * @param source script source 1546 * 1547 * @return result of load (may be undefined) 1548 * 1549 * @throws IOException if source could not be read 1550 */ 1551 public static Object load(final Object self, final Object source) throws IOException { 1552 final Global global = Global.instanceFrom(self); 1553 return global.getContext().load(self, source); 1554 } 1555 1556 /** 1557 * Global loadWithNewGlobal implementation - Nashorn extension. 1558 * 1559 * loadWithNewGlobal builtin loads the given script from a URL or a File 1560 * or a script object with name and script properties. Evaluated code gets 1561 * new global object "this" and uses that new global object as scope for evaluation. 1562 * 1563 * @param self self This value is ignored by this function 1564 * @param args optional arguments to be passed to the loaded script 1565 * 1566 * @return result of load (may be undefined) 1567 * 1568 * @throws IOException if source could not be read 1569 */ 1570 public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException { 1571 final Global global = Global.instanceFrom(self); 1572 final int length = args.length; 1573 final boolean hasArgs = 0 < length; 1574 final Object from = hasArgs ? args[0] : UNDEFINED; 1575 final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args; 1576 1577 return global.getContext().loadWithNewGlobal(from, arguments); 1578 } 1579 1580 /** 1581 * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script 1582 * 1583 * @param self self reference 1584 * @param code exit code 1585 * 1586 * @return undefined (will never be reached) 1587 */ 1588 public static Object exit(final Object self, final Object code) { 1589 System.exit(JSType.toInt32(code)); 1590 return UNDEFINED; 1591 } 1592 1593 // builtin prototype accessors 1594 1595 /** 1596 * Get the builtin Object prototype. 1597 * @return the Object prototype. 1598 */ 1599 public ScriptObject getObjectPrototype() { 1600 return ScriptFunction.getPrototype(builtinObject); 1601 } 1602 1603 /** 1604 * Get the builtin Function prototype. 1605 * @return the Function prototype. 1606 */ 1607 public ScriptObject getFunctionPrototype() { 1608 return ScriptFunction.getPrototype(builtinFunction); 1609 } 1610 1611 /** 1612 * Get the builtin Array prototype. 1613 * @return the Array prototype 1614 */ 1615 public ScriptObject getArrayPrototype() { 1616 return ScriptFunction.getPrototype(builtinArray); 1617 } 1618 1619 ScriptObject getBooleanPrototype() { 1620 return ScriptFunction.getPrototype(builtinBoolean); 1621 } 1622 1623 ScriptObject getNumberPrototype() { 1624 return ScriptFunction.getPrototype(builtinNumber); 1625 } 1626 1627 ScriptObject getDatePrototype() { 1628 return ScriptFunction.getPrototype(getBuiltinDate()); 1629 } 1630 1631 ScriptObject getRegExpPrototype() { 1632 return ScriptFunction.getPrototype(getBuiltinRegExp()); 1633 } 1634 1635 ScriptObject getStringPrototype() { 1636 return ScriptFunction.getPrototype(builtinString); 1637 } 1638 1639 ScriptObject getErrorPrototype() { 1640 return ScriptFunction.getPrototype(builtinError); 1641 } 1642 1643 ScriptObject getEvalErrorPrototype() { 1644 return ScriptFunction.getPrototype(getBuiltinEvalError()); 1645 } 1646 1647 ScriptObject getRangeErrorPrototype() { 1648 return ScriptFunction.getPrototype(getBuiltinRangeError()); 1649 } 1650 1651 ScriptObject getReferenceErrorPrototype() { 1652 return ScriptFunction.getPrototype(builtinReferenceError); 1653 } 1654 1655 ScriptObject getSyntaxErrorPrototype() { 1656 return ScriptFunction.getPrototype(builtinSyntaxError); 1657 } 1658 1659 ScriptObject getTypeErrorPrototype() { 1660 return ScriptFunction.getPrototype(builtinTypeError); 1661 } 1662 1663 ScriptObject getURIErrorPrototype() { 1664 return ScriptFunction.getPrototype(getBuiltinURIError()); 1665 } 1666 1667 ScriptObject getJavaImporterPrototype() { 1668 return ScriptFunction.getPrototype(getBuiltinJavaImporter()); 1669 } 1670 1671 ScriptObject getJSAdapterPrototype() { 1672 return ScriptFunction.getPrototype(getBuiltinJSAdapter()); 1673 } 1674 1675 ScriptObject getSymbolPrototype() { 1676 return ScriptFunction.getPrototype(builtinSymbol); 1677 } 1678 1679 private synchronized ScriptFunction getBuiltinArrayBuffer() { 1680 if (this.builtinArrayBuffer == null) { 1681 this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class); 1682 } 1683 return this.builtinArrayBuffer; 1684 } 1685 1686 ScriptObject getArrayBufferPrototype() { 1687 return ScriptFunction.getPrototype(getBuiltinArrayBuffer()); 1688 } 1689 1690 private synchronized ScriptFunction getBuiltinDataView() { 1691 if (this.builtinDataView == null) { 1692 this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class); 1693 } 1694 return this.builtinDataView; 1695 } 1696 1697 ScriptObject getDataViewPrototype() { 1698 return ScriptFunction.getPrototype(getBuiltinDataView()); 1699 } 1700 1701 private synchronized ScriptFunction getBuiltinInt8Array() { 1702 if (this.builtinInt8Array == null) { 1703 this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class); 1704 } 1705 return this.builtinInt8Array; 1706 } 1707 1708 ScriptObject getInt8ArrayPrototype() { 1709 return ScriptFunction.getPrototype(getBuiltinInt8Array()); 1710 } 1711 1712 private synchronized ScriptFunction getBuiltinUint8Array() { 1713 if (this.builtinUint8Array == null) { 1714 this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class); 1715 } 1716 return this.builtinUint8Array; 1717 } 1718 1719 ScriptObject getUint8ArrayPrototype() { 1720 return ScriptFunction.getPrototype(getBuiltinUint8Array()); 1721 } 1722 1723 private synchronized ScriptFunction getBuiltinUint8ClampedArray() { 1724 if (this.builtinUint8ClampedArray == null) { 1725 this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class); 1726 } 1727 return this.builtinUint8ClampedArray; 1728 } 1729 1730 ScriptObject getUint8ClampedArrayPrototype() { 1731 return ScriptFunction.getPrototype(getBuiltinUint8ClampedArray()); 1732 } 1733 1734 private synchronized ScriptFunction getBuiltinInt16Array() { 1735 if (this.builtinInt16Array == null) { 1736 this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class); 1737 } 1738 return this.builtinInt16Array; 1739 } 1740 1741 ScriptObject getInt16ArrayPrototype() { 1742 return ScriptFunction.getPrototype(getBuiltinInt16Array()); 1743 } 1744 1745 private synchronized ScriptFunction getBuiltinUint16Array() { 1746 if (this.builtinUint16Array == null) { 1747 this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class); 1748 } 1749 return this.builtinUint16Array; 1750 } 1751 1752 ScriptObject getUint16ArrayPrototype() { 1753 return ScriptFunction.getPrototype(getBuiltinUint16Array()); 1754 } 1755 1756 private synchronized ScriptFunction getBuiltinInt32Array() { 1757 if (this.builtinInt32Array == null) { 1758 this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class); 1759 } 1760 return this.builtinInt32Array; 1761 } 1762 1763 ScriptObject getInt32ArrayPrototype() { 1764 return ScriptFunction.getPrototype(getBuiltinInt32Array()); 1765 } 1766 1767 private synchronized ScriptFunction getBuiltinUint32Array() { 1768 if (this.builtinUint32Array == null) { 1769 this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class); 1770 } 1771 return this.builtinUint32Array; 1772 } 1773 1774 ScriptObject getUint32ArrayPrototype() { 1775 return ScriptFunction.getPrototype(getBuiltinUint32Array()); 1776 } 1777 1778 private synchronized ScriptFunction getBuiltinFloat32Array() { 1779 if (this.builtinFloat32Array == null) { 1780 this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class); 1781 } 1782 return this.builtinFloat32Array; 1783 } 1784 1785 ScriptObject getFloat32ArrayPrototype() { 1786 return ScriptFunction.getPrototype(getBuiltinFloat32Array()); 1787 } 1788 1789 private synchronized ScriptFunction getBuiltinFloat64Array() { 1790 if (this.builtinFloat64Array == null) { 1791 this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class); 1792 } 1793 return this.builtinFloat64Array; 1794 } 1795 1796 ScriptObject getFloat64ArrayPrototype() { 1797 return ScriptFunction.getPrototype(getBuiltinFloat64Array()); 1798 } 1799 1800 /** 1801 * Return the function that throws TypeError unconditionally. Used as "poison" methods for certain Function properties. 1802 * 1803 * @return the TypeError throwing function 1804 */ 1805 public ScriptFunction getTypeErrorThrower() { 1806 return typeErrorThrower; 1807 } 1808 1809 private synchronized ScriptFunction getBuiltinDate() { 1810 if (this.builtinDate == null) { 1811 this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class); 1812 final ScriptObject dateProto = ScriptFunction.getPrototype(builtinDate); 1813 // initialize default date 1814 this.DEFAULT_DATE = new NativeDate(NaN, dateProto); 1815 } 1816 return this.builtinDate; 1817 } 1818 1819 private synchronized ScriptFunction getBuiltinEvalError() { 1820 if (this.builtinEvalError == null) { 1821 this.builtinEvalError = initErrorSubtype("EvalError", getErrorPrototype()); 1822 } 1823 return this.builtinEvalError; 1824 } 1825 1826 private ScriptFunction getBuiltinFunction() { 1827 return builtinFunction; 1828 } 1829 1830 /** 1831 * Get the switchpoint used to check property changes for Function.prototype.apply 1832 * @return the switchpoint guarding apply (same as guarding call, and everything else in function) 1833 */ 1834 public static SwitchPoint getBuiltinFunctionApplySwitchPoint() { 1835 return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint(); 1836 } 1837 1838 private static boolean isBuiltinFunctionProperty(final String name) { 1839 final Global instance = Global.instance(); 1840 final ScriptFunction builtinFunction = instance.getBuiltinFunction(); 1841 if (builtinFunction == null) { 1842 return false; //conservative for compile-only mode 1843 } 1844 final boolean isBuiltinFunction = instance.function == builtinFunction; 1845 return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin(); 1846 } 1847 1848 /** 1849 * Check if the Function.prototype.apply has not been replaced 1850 * @return true if Function.prototype.apply has been replaced 1851 */ 1852 public static boolean isBuiltinFunctionPrototypeApply() { 1853 return isBuiltinFunctionProperty("apply"); 1854 } 1855 1856 /** 1857 * Check if the Function.prototype.apply has not been replaced 1858 * @return true if Function.prototype.call has been replaced 1859 */ 1860 public static boolean isBuiltinFunctionPrototypeCall() { 1861 return isBuiltinFunctionProperty("call"); 1862 } 1863 1864 private synchronized ScriptFunction getBuiltinJSAdapter() { 1865 if (this.builtinJSAdapter == null) { 1866 this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class); 1867 } 1868 return builtinJSAdapter; 1869 } 1870 1871 private synchronized ScriptObject getBuiltinJSON() { 1872 if (this.builtinJSON == null) { 1873 this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class); 1874 } 1875 return this.builtinJSON; 1876 } 1877 1878 private synchronized ScriptFunction getBuiltinJavaImporter() { 1879 if (this.builtinJavaImporter == null) { 1880 this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class); 1881 } 1882 return this.builtinJavaImporter; 1883 } 1884 1885 private synchronized ScriptObject getBuiltinJavaApi() { 1886 if (this.builtinJavaApi == null) { 1887 this.builtinJavaApi = initConstructor("Java", ScriptObject.class); 1888 } 1889 return this.builtinJavaApi; 1890 } 1891 1892 private synchronized ScriptFunction getBuiltinRangeError() { 1893 if (this.builtinRangeError == null) { 1894 this.builtinRangeError = initErrorSubtype("RangeError", getErrorPrototype()); 1895 } 1896 return builtinRangeError; 1897 } 1898 1899 private synchronized ScriptFunction getBuiltinRegExp() { 1900 if (this.builtinRegExp == null) { 1901 this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class); 1902 final ScriptObject regExpProto = ScriptFunction.getPrototype(builtinRegExp); 1903 // initialize default regexp object 1904 this.DEFAULT_REGEXP = new NativeRegExp("(?:)", "", this, regExpProto); 1905 // RegExp.prototype should behave like a RegExp object. So copy the 1906 // properties. 1907 regExpProto.addBoundProperties(DEFAULT_REGEXP); 1908 } 1909 return builtinRegExp; 1910 } 1911 1912 private synchronized ScriptFunction getBuiltinURIError() { 1913 if (this.builtinURIError == null) { 1914 this.builtinURIError = initErrorSubtype("URIError", getErrorPrototype()); 1915 } 1916 return this.builtinURIError; 1917 } 1918 1919 @Override 1920 public String getClassName() { 1921 return "global"; 1922 } 1923 1924 /** 1925 * Copy function used to clone NativeRegExp objects. 1926 * 1927 * @param regexp a NativeRegExp to clone 1928 * 1929 * @return copy of the given regexp object 1930 */ 1931 public static Object regExpCopy(final Object regexp) { 1932 return new NativeRegExp((NativeRegExp)regexp); 1933 } 1934 1935 /** 1936 * Convert given object to NativeRegExp type. 1937 * 1938 * @param obj object to be converted 1939 * @return NativeRegExp instance 1940 */ 1941 public static NativeRegExp toRegExp(final Object obj) { 1942 if (obj instanceof NativeRegExp) { 1943 return (NativeRegExp)obj; 1944 } 1945 return new NativeRegExp(JSType.toString(obj)); 1946 } 1947 1948 /** 1949 * ECMA 9.9 ToObject implementation 1950 * 1951 * @param obj an item for which to run ToObject 1952 * @return ToObject version of given item 1953 */ 1954 public static Object toObject(final Object obj) { 1955 if (obj == null || obj == UNDEFINED) { 1956 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1957 } 1958 1959 if (obj instanceof ScriptObject) { 1960 return obj; 1961 } 1962 1963 return instance().wrapAsObject(obj); 1964 } 1965 1966 /** 1967 * Allocate a new object array. 1968 * 1969 * @param initial object values. 1970 * @return the new array 1971 */ 1972 public static NativeArray allocate(final Object[] initial) { 1973 ArrayData arrayData = ArrayData.allocate(initial); 1974 1975 for (int index = 0; index < initial.length; index++) { 1976 final Object value = initial[index]; 1977 1978 if (value == ScriptRuntime.EMPTY) { 1979 arrayData = arrayData.delete(index); 1980 } 1981 } 1982 1983 return new NativeArray(arrayData); 1984 } 1985 1986 /** 1987 * Allocate a new number array. 1988 * 1989 * @param initial number values. 1990 * @return the new array 1991 */ 1992 public static NativeArray allocate(final double[] initial) { 1993 return new NativeArray(ArrayData.allocate(initial)); 1994 } 1995 1996 /** 1997 * Allocate a new integer array. 1998 * 1999 * @param initial number values. 2000 * @return the new array 2001 */ 2002 public static NativeArray allocate(final int[] initial) { 2003 return new NativeArray(ArrayData.allocate(initial)); 2004 } 2005 2006 /** 2007 * Allocate a new object array for arguments. 2008 * 2009 * @param arguments initial arguments passed. 2010 * @param callee reference to the function that uses arguments object 2011 * @param numParams actual number of declared parameters 2012 * 2013 * @return the new array 2014 */ 2015 public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) { 2016 return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams); 2017 } 2018 2019 /** 2020 * Called from generated to check if given function is the builtin 'eval'. If 2021 * eval is used in a script, a lot of optimizations and assumptions cannot be done. 2022 * 2023 * @param fn function object that is checked 2024 * @return true if fn is the builtin eval 2025 */ 2026 public static boolean isEval(final Object fn) { 2027 return fn == Global.instance().builtinEval; 2028 } 2029 2030 /** 2031 * Called from generated to replace a location property placeholder with the actual location property value. 2032 * 2033 * @param placeholder the value tested for being a placeholder for a location property 2034 * @param locationProperty the actual value for the location property 2035 * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise 2036 */ 2037 public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) { 2038 return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder; 2039 } 2040 2041 /** 2042 * Called from runtime internals to check if the passed value is a location property placeholder. 2043 * @param placeholder the value tested for being a placeholder for a location property 2044 * @return true if the value is a placeholder, false otherwise. 2045 */ 2046 public static boolean isLocationPropertyPlaceholder(final Object placeholder) { 2047 return placeholder == LAZY_SENTINEL; 2048 } 2049 2050 /** 2051 * Create a new RegExp object. 2052 * 2053 * @param expression Regular expression. 2054 * @param options Search options. 2055 * 2056 * @return New RegExp object. 2057 */ 2058 public static Object newRegExp(final String expression, final String options) { 2059 if (options == null) { 2060 return new NativeRegExp(expression); 2061 } 2062 return new NativeRegExp(expression, options); 2063 } 2064 2065 /** 2066 * Get the object prototype 2067 * 2068 * @return the object prototype 2069 */ 2070 public static ScriptObject objectPrototype() { 2071 return Global.instance().getObjectPrototype(); 2072 } 2073 2074 /** 2075 * Create a new empty object instance. 2076 * 2077 * @return New empty object. 2078 */ 2079 public static ScriptObject newEmptyInstance() { 2080 return Global.instance().newObject(); 2081 } 2082 2083 /** 2084 * Check if a given object is a ScriptObject, raises an exception if this is 2085 * not the case 2086 * 2087 * @param obj and object to check 2088 * @return the script object 2089 */ 2090 public static ScriptObject checkObject(final Object obj) { 2091 if (!(obj instanceof ScriptObject)) { 2092 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 2093 } 2094 return (ScriptObject)obj; 2095 } 2096 2097 /** 2098 * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception 2099 * if this object is null or undefined. 2100 * 2101 * @param obj an object to check 2102 */ 2103 public static void checkObjectCoercible(final Object obj) { 2104 if (obj == null || obj == UNDEFINED) { 2105 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 2106 } 2107 } 2108 2109 /** 2110 * Return the ES6 global scope for lexically declared bindings. 2111 * @return the ES6 lexical global scope. 2112 */ 2113 public final ScriptObject getLexicalScope() { 2114 assert context.getEnv()._es6; 2115 return lexicalScope; 2116 } 2117 2118 @Override 2119 public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) { 2120 PropertyMap ownMap = getMap(); 2121 LexicalScope lexScope = null; 2122 PropertyMap lexicalMap = null; 2123 boolean hasLexicalDefinitions = false; 2124 2125 if (context.getEnv()._es6) { 2126 lexScope = (LexicalScope) getLexicalScope(); 2127 lexicalMap = lexScope.getMap(); 2128 2129 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2130 if (property.isLexicalBinding()) { 2131 hasLexicalDefinitions = true; 2132 } 2133 // ES6 15.1.8 steps 6. and 7. 2134 final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey()); 2135 if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) { 2136 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString()); 2137 } 2138 final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey()); 2139 if (lexicalProperty != null && !property.isConfigurable()) { 2140 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString()); 2141 } 2142 } 2143 } 2144 2145 final boolean extensible = isExtensible(); 2146 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2147 if (property.isLexicalBinding()) { 2148 assert lexScope != null; 2149 lexicalMap = lexScope.addBoundProperty(lexicalMap, source, property, true); 2150 2151 if (ownMap.findProperty(property.getKey()) != null) { 2152 // If property exists in the global object invalidate any global constant call sites. 2153 invalidateGlobalConstant(property.getKey()); 2154 } 2155 } else { 2156 ownMap = addBoundProperty(ownMap, source, property, extensible); 2157 } 2158 } 2159 2160 setMap(ownMap); 2161 2162 if (hasLexicalDefinitions) { 2163 assert lexScope != null; 2164 lexScope.setMap(lexicalMap); 2165 invalidateLexicalSwitchPoint(); 2166 } 2167 } 2168 2169 @Override 2170 public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { 2171 final String name = NashornCallSiteDescriptor.getOperand(desc); 2172 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 2173 2174 if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { 2175 if (lexicalScope.hasOwnProperty(name)) { 2176 return lexicalScope.findGetMethod(desc, request, operation); 2177 } 2178 } 2179 2180 final GuardedInvocation invocation = super.findGetMethod(desc, request, operation); 2181 2182 // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, 2183 // because those are invalidated per-key in the addBoundProperties method above. 2184 // We therefore check if the invocation does already have a switchpoint and the property is non-inherited, 2185 // assuming this only applies to global constants. If other non-inherited properties will 2186 // start using switchpoints some time in the future we'll have to revisit this. 2187 if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { 2188 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 2189 } 2190 2191 return invocation; 2192 } 2193 2194 @Override 2195 protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) { 2196 if (lexicalScope != null && start != this && start.isScope()) { 2197 final FindProperty find = lexicalScope.findProperty(key, false); 2198 if (find != null) { 2199 return find; 2200 } 2201 } 2202 return super.findProperty(key, deep, start); 2203 } 2204 2205 @Override 2206 public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 2207 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 2208 2209 if (lexicalScope != null && isScope) { 2210 final String name = NashornCallSiteDescriptor.getOperand(desc); 2211 if (lexicalScope.hasOwnProperty(name)) { 2212 return lexicalScope.findSetMethod(desc, request); 2213 } 2214 } 2215 2216 final GuardedInvocation invocation = super.findSetMethod(desc, request); 2217 2218 if (isScope && context.getEnv()._es6) { 2219 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 2220 } 2221 2222 return invocation; 2223 } 2224 2225 /** 2226 * Adds jjs shell interactive mode builtin functions to global scope. 2227 */ 2228 public void addShellBuiltins() { 2229 Object value = ScriptFunction.createBuiltin("input", ShellFunctions.INPUT); 2230 addOwnProperty("input", Attribute.NOT_ENUMERABLE, value); 2231 2232 value = ScriptFunction.createBuiltin("evalinput", ShellFunctions.EVALINPUT); 2233 addOwnProperty("evalinput", Attribute.NOT_ENUMERABLE, value); 2234 } 2235 2236 private synchronized SwitchPoint getLexicalScopeSwitchPoint() { 2237 SwitchPoint switchPoint = lexicalScopeSwitchPoint; 2238 if (switchPoint == null || switchPoint.hasBeenInvalidated()) { 2239 switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); 2240 } 2241 return switchPoint; 2242 } 2243 2244 private synchronized void invalidateLexicalSwitchPoint() { 2245 if (lexicalScopeSwitchPoint != null) { 2246 context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); 2247 SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); 2248 } 2249 } 2250 2251 2252 @SuppressWarnings("unused") 2253 private static Object lexicalScopeFilter(final Object self) { 2254 if (self instanceof Global) { 2255 return ((Global) self).getLexicalScope(); 2256 } 2257 return self; 2258 } 2259 2260 private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) { 2261 final T func = initConstructor(name, clazz); 2262 tagBuiltinProperties(name, func); 2263 return func; 2264 } 2265 2266 private void init(final ScriptEngine eng) { 2267 assert Context.getGlobal() == this : "this global is not set as current"; 2268 2269 final ScriptEnvironment env = getContext().getEnv(); 2270 2271 // initialize Function and Object constructor 2272 initFunctionAndObject(); 2273 2274 // Now fix Global's own proto. 2275 this.setInitialProto(getObjectPrototype()); 2276 2277 // initialize global function properties 2278 this.eval = this.builtinEval = ScriptFunction.createBuiltin("eval", EVAL); 2279 2280 this.parseInt = ScriptFunction.createBuiltin("parseInt", GlobalFunctions.PARSEINT, 2281 new Specialization[] { 2282 new Specialization(GlobalFunctions.PARSEINT_Z), 2283 new Specialization(GlobalFunctions.PARSEINT_I), 2284 new Specialization(GlobalFunctions.PARSEINT_OI), 2285 new Specialization(GlobalFunctions.PARSEINT_O) }); 2286 this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT); 2287 this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN, 2288 new Specialization[] { 2289 new Specialization(GlobalFunctions.IS_NAN_I), 2290 new Specialization(GlobalFunctions.IS_NAN_J), 2291 new Specialization(GlobalFunctions.IS_NAN_D) }); 2292 this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT); 2293 this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN); 2294 this.isFinite = ScriptFunction.createBuiltin("isFinite", GlobalFunctions.IS_FINITE); 2295 this.encodeURI = ScriptFunction.createBuiltin("encodeURI", GlobalFunctions.ENCODE_URI); 2296 this.encodeURIComponent = ScriptFunction.createBuiltin("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT); 2297 this.decodeURI = ScriptFunction.createBuiltin("decodeURI", GlobalFunctions.DECODE_URI); 2298 this.decodeURIComponent = ScriptFunction.createBuiltin("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); 2299 this.escape = ScriptFunction.createBuiltin("escape", GlobalFunctions.ESCAPE); 2300 this.unescape = ScriptFunction.createBuiltin("unescape", GlobalFunctions.UNESCAPE); 2301 this.print = ScriptFunction.createBuiltin("print", env._print_no_newline ? PRINT : PRINTLN); 2302 this.load = ScriptFunction.createBuiltin("load", LOAD); 2303 this.loadWithNewGlobal = ScriptFunction.createBuiltin("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); 2304 this.exit = ScriptFunction.createBuiltin("exit", EXIT); 2305 this.quit = ScriptFunction.createBuiltin("quit", EXIT); 2306 2307 // built-in constructors 2308 this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class); 2309 this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class); 2310 this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class); 2311 this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class); 2312 this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class); 2313 2314 if (env._es6) { 2315 this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class); 2316 } else { 2317 // We need to manually delete nasgen-generated properties we don't want 2318 this.delete("Symbol", false); 2319 this.builtinObject.delete("getOwnPropertySymbols", false); 2320 } 2321 2322 // initialize String.prototype.length to 0 2323 // add String.prototype.length 2324 final ScriptObject stringPrototype = getStringPrototype(); 2325 stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0); 2326 2327 // set isArray flag on Array.prototype 2328 final ScriptObject arrayPrototype = getArrayPrototype(); 2329 arrayPrototype.setIsArray(); 2330 2331 // Error stuff 2332 initErrorObjects(); 2333 2334 // java access 2335 if (! env._no_java) { 2336 this.javaApi = LAZY_SENTINEL; 2337 this.javaImporter = LAZY_SENTINEL; 2338 initJavaAccess(); 2339 } 2340 2341 if (! env._no_typed_arrays) { 2342 this.arrayBuffer = LAZY_SENTINEL; 2343 this.dataView = LAZY_SENTINEL; 2344 this.int8Array = LAZY_SENTINEL; 2345 this.uint8Array = LAZY_SENTINEL; 2346 this.uint8ClampedArray = LAZY_SENTINEL; 2347 this.int16Array = LAZY_SENTINEL; 2348 this.uint16Array = LAZY_SENTINEL; 2349 this.int32Array = LAZY_SENTINEL; 2350 this.uint32Array = LAZY_SENTINEL; 2351 this.float32Array = LAZY_SENTINEL; 2352 this.float64Array = LAZY_SENTINEL; 2353 } 2354 2355 if (env._scripting) { 2356 initScripting(env); 2357 } 2358 2359 if (Context.DEBUG) { 2360 boolean debugOkay; 2361 final SecurityManager sm = System.getSecurityManager(); 2362 if (sm != null) { 2363 try { 2364 sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE)); 2365 debugOkay = true; 2366 } catch (final SecurityException ignored) { 2367 // if no permission, don't initialize Debug object 2368 debugOkay = false; 2369 } 2370 2371 } else { 2372 debugOkay = true; 2373 } 2374 2375 if (debugOkay) { 2376 initDebug(); 2377 } 2378 } 2379 2380 copyBuiltins(); 2381 2382 // expose script (command line) arguments as "arguments" property of global 2383 arguments = wrapAsObject(env.getArguments().toArray()); 2384 if (env._scripting) { 2385 // synonym for "arguments" in scripting mode 2386 addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); 2387 } 2388 2389 if (eng != null) { 2390 // default file name 2391 addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); 2392 // __noSuchProperty__ hook for ScriptContext search of missing variables 2393 final ScriptFunction noSuchProp = ScriptFunction.createStrictBuiltin(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY); 2394 addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp); 2395 } 2396 } 2397 2398 private void initErrorObjects() { 2399 // Error objects 2400 this.builtinError = initConstructor("Error", ScriptFunction.class); 2401 final ScriptObject errorProto = getErrorPrototype(); 2402 2403 // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName 2404 final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", NativeError.GET_STACK); 2405 final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", NativeError.SET_STACK); 2406 errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); 2407 final ScriptFunction getLineNumber = ScriptFunction.createBuiltin("getLineNumber", NativeError.GET_LINENUMBER); 2408 final ScriptFunction setLineNumber = ScriptFunction.createBuiltin("setLineNumber", NativeError.SET_LINENUMBER); 2409 errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber); 2410 final ScriptFunction getColumnNumber = ScriptFunction.createBuiltin("getColumnNumber", NativeError.GET_COLUMNNUMBER); 2411 final ScriptFunction setColumnNumber = ScriptFunction.createBuiltin("setColumnNumber", NativeError.SET_COLUMNNUMBER); 2412 errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber); 2413 final ScriptFunction getFileName = ScriptFunction.createBuiltin("getFileName", NativeError.GET_FILENAME); 2414 final ScriptFunction setFileName = ScriptFunction.createBuiltin("setFileName", NativeError.SET_FILENAME); 2415 errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName); 2416 2417 // ECMA 15.11.4.2 Error.prototype.name 2418 // Error.prototype.name = "Error"; 2419 errorProto.set(NativeError.NAME, "Error", 0); 2420 // ECMA 15.11.4.3 Error.prototype.message 2421 // Error.prototype.message = ""; 2422 errorProto.set(NativeError.MESSAGE, "", 0); 2423 2424 tagBuiltinProperties("Error", builtinError); 2425 2426 this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto); 2427 this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto); 2428 this.builtinTypeError = initErrorSubtype("TypeError", errorProto); 2429 } 2430 2431 private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { 2432 final ScriptFunction cons = initConstructor(name, ScriptFunction.class); 2433 final ScriptObject prototype = ScriptFunction.getPrototype(cons); 2434 prototype.set(NativeError.NAME, name, 0); 2435 prototype.set(NativeError.MESSAGE, "", 0); 2436 prototype.setInitialProto(errorProto); 2437 tagBuiltinProperties(name, cons); 2438 return cons; 2439 } 2440 2441 private void initJavaAccess() { 2442 final ScriptObject objectProto = getObjectPrototype(); 2443 this.builtinPackages = new NativeJavaPackage("", objectProto); 2444 this.builtinCom = new NativeJavaPackage("com", objectProto); 2445 this.builtinEdu = new NativeJavaPackage("edu", objectProto); 2446 this.builtinJava = new NativeJavaPackage("java", objectProto); 2447 this.builtinJavafx = new NativeJavaPackage("javafx", objectProto); 2448 this.builtinJavax = new NativeJavaPackage("javax", objectProto); 2449 this.builtinOrg = new NativeJavaPackage("org", objectProto); 2450 } 2451 2452 private void initScripting(final ScriptEnvironment scriptEnv) { 2453 ScriptObject value; 2454 value = ScriptFunction.createBuiltin("readLine", ScriptingFunctions.READLINE); 2455 addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); 2456 2457 value = ScriptFunction.createBuiltin("readFully", ScriptingFunctions.READFULLY); 2458 addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); 2459 2460 final String execName = ScriptingFunctions.EXEC_NAME; 2461 value = ScriptFunction.createBuiltin(execName, ScriptingFunctions.EXEC); 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 final ScriptObject env = newObject(); 2476 if (System.getSecurityManager() == null) { 2477 // do not fill $ENV if we have a security manager around 2478 // Retrieve current state of ENV variables. 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 2490 // add other special properties for exec support 2491 addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2492 addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2493 addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2494 } 2495 2496 private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { 2497 for (final Field f : scriptEnv.getClass().getFields()) { 2498 try { 2499 options.set(f.getName(), f.get(scriptEnv), 0); 2500 } catch (final IllegalArgumentException | IllegalAccessException exp) { 2501 throw new RuntimeException(exp); 2502 } 2503 } 2504 } 2505 2506 private void copyBuiltins() { 2507 this.array = this.builtinArray; 2508 this._boolean = this.builtinBoolean; 2509 this.error = this.builtinError; 2510 this.function = this.builtinFunction; 2511 this.com = this.builtinCom; 2512 this.edu = this.builtinEdu; 2513 this.java = this.builtinJava; 2514 this.javafx = this.builtinJavafx; 2515 this.javax = this.builtinJavax; 2516 this.org = this.builtinOrg; 2517 this.math = this.builtinMath; 2518 this.number = this.builtinNumber; 2519 this.object = this.builtinObject; 2520 this.packages = this.builtinPackages; 2521 this.referenceError = this.builtinReferenceError; 2522 this.string = this.builtinString; 2523 this.syntaxError = this.builtinSyntaxError; 2524 this.typeError = this.builtinTypeError; 2525 this.symbol = this.builtinSymbol; 2526 } 2527 2528 private void initDebug() { 2529 this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class)); 2530 } 2531 2532 private Object printImpl(final boolean newLine, final Object... objects) { 2533 final ScriptContext sc = currentContext(); 2534 @SuppressWarnings("resource") 2535 final PrintWriter out = sc != null? new PrintWriter(sc.getWriter()) : getContext().getEnv().getOut(); 2536 final StringBuilder sb = new StringBuilder(); 2537 2538 for (final Object obj : objects) { 2539 if (sb.length() != 0) { 2540 sb.append(' '); 2541 } 2542 2543 sb.append(JSType.toString(obj)); 2544 } 2545 2546 // Print all at once to ensure thread friendly result. 2547 if (newLine) { 2548 out.println(sb.toString()); 2549 } else { 2550 out.print(sb.toString()); 2551 } 2552 2553 out.flush(); 2554 2555 return UNDEFINED; 2556 } 2557 2558 private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) { 2559 try { 2560 // Assuming class name pattern for built-in JS constructors. 2561 final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects."); 2562 2563 sb.append("Native"); 2564 sb.append(name); 2565 sb.append("$Constructor"); 2566 2567 final Class<?> funcClass = Class.forName(sb.toString()); 2568 final T res = clazz.cast(funcClass.newInstance()); 2569 2570 if (res instanceof ScriptFunction) { 2571 // All global constructor prototypes are not-writable, 2572 // not-enumerable and not-configurable. 2573 final ScriptFunction func = (ScriptFunction)res; 2574 func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT); 2575 } 2576 2577 if (res.getProto() == null) { 2578 res.setInitialProto(getObjectPrototype()); 2579 } 2580 2581 res.setIsBuiltin(); 2582 2583 return res; 2584 } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { 2585 throw new RuntimeException(e); 2586 } 2587 } 2588 2589 private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) { 2590 final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>(); 2591 2592 list.addAll(Arrays.asList(func.getMap().getProperties())); 2593 2594 if (func instanceof ScriptFunction) { 2595 final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func); 2596 if (proto != null) { 2597 list.addAll(Arrays.asList(proto.getMap().getProperties())); 2598 } 2599 } 2600 2601 final jdk.nashorn.internal.runtime.Property prop = getProperty(name); 2602 if (prop != null) { 2603 list.add(prop); 2604 } 2605 2606 return list; 2607 } 2608 2609 /** 2610 * Given a builtin object, traverse its properties recursively and associate them with a name that 2611 * will be a key to their invalidation switchpoint. 2612 * @param name name for key 2613 * @param func builtin script object 2614 */ 2615 private void tagBuiltinProperties(final String name, final ScriptObject func) { 2616 SwitchPoint sp = context.getBuiltinSwitchPoint(name); 2617 if (sp == null) { 2618 sp = context.newBuiltinSwitchPoint(name); 2619 } 2620 2621 //get all builtin properties in this builtin object and register switchpoints keyed on the propery name, 2622 //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc 2623 for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) { 2624 prop.setBuiltinSwitchPoint(sp); 2625 } 2626 } 2627 2628 // Function and Object constructors are inter-dependent. Also, 2629 // Function.prototype 2630 // functions are not properly initialized. We fix the references here. 2631 // NOTE: be careful if you want to re-order the operations here. You may 2632 // have 2633 // to play with object references carefully!! 2634 private void initFunctionAndObject() { 2635 // First-n-foremost is Function 2636 2637 this.builtinFunction = initConstructor("Function", ScriptFunction.class); 2638 2639 // create global anonymous function 2640 final ScriptFunction anon = ScriptFunction.createAnonymous(); 2641 // need to copy over members of Function.prototype to anon function 2642 anon.addBoundProperties(getFunctionPrototype()); 2643 2644 // Function.prototype === Object.getPrototypeOf(Function) === 2645 // <anon-function> 2646 builtinFunction.setInitialProto(anon); 2647 builtinFunction.setPrototype(anon); 2648 anon.set("constructor", builtinFunction, 0); 2649 anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); 2650 2651 // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 2652 this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER); 2653 typeErrorThrower.preventExtensions(); 2654 2655 // now initialize Object 2656 this.builtinObject = initConstructor("Object", ScriptFunction.class); 2657 final ScriptObject ObjectPrototype = getObjectPrototype(); 2658 // Object.getPrototypeOf(Function.prototype) === Object.prototype 2659 anon.setInitialProto(ObjectPrototype); 2660 2661 // ES6 draft compliant __proto__ property of Object.prototype 2662 // accessors on Object.prototype for "__proto__" 2663 final ScriptFunction getProto = ScriptFunction.createBuiltin("getProto", NativeObject.GET__PROTO__); 2664 final ScriptFunction setProto = ScriptFunction.createBuiltin("setProto", NativeObject.SET__PROTO__); 2665 ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); 2666 2667 // Function valued properties of Function.prototype were not properly 2668 // initialized. Because, these were created before global.function and 2669 // global.object were not initialized. 2670 jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties(); 2671 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2672 final Object key = property.getKey(); 2673 final Object value = builtinFunction.get(key); 2674 2675 if (value instanceof ScriptFunction && value != anon) { 2676 final ScriptFunction func = (ScriptFunction)value; 2677 func.setInitialProto(getFunctionPrototype()); 2678 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2679 if (prototype != null) { 2680 prototype.setInitialProto(ObjectPrototype); 2681 } 2682 } 2683 } 2684 2685 // For function valued properties of Object and Object.prototype, make 2686 // sure prototype's proto chain ends with Object.prototype 2687 for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) { 2688 final Object key = property.getKey(); 2689 final Object value = builtinObject.get(key); 2690 2691 if (value instanceof ScriptFunction) { 2692 final ScriptFunction func = (ScriptFunction)value; 2693 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2694 if (prototype != null) { 2695 prototype.setInitialProto(ObjectPrototype); 2696 } 2697 } 2698 } 2699 2700 properties = getObjectPrototype().getMap().getProperties(); 2701 2702 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2703 final Object key = property.getKey(); 2704 if (key.equals("constructor")) { 2705 continue; 2706 } 2707 2708 final Object value = ObjectPrototype.get(key); 2709 if (value instanceof ScriptFunction) { 2710 final ScriptFunction func = (ScriptFunction)value; 2711 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2712 if (prototype != null) { 2713 prototype.setInitialProto(ObjectPrototype); 2714 } 2715 } 2716 } 2717 2718 tagBuiltinProperties("Object", builtinObject); 2719 tagBuiltinProperties("Function", builtinFunction); 2720 tagBuiltinProperties("Function", anon); 2721 } 2722 2723 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) { 2724 return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types)); 2725 } 2726 2727 RegExpResult getLastRegExpResult() { 2728 return lastRegExpResult; 2729 } 2730 2731 void setLastRegExpResult(final RegExpResult regExpResult) { 2732 this.lastRegExpResult = regExpResult; 2733 } 2734 2735 @Override 2736 protected boolean isGlobal() { 2737 return true; 2738 } 2739 2740 /** 2741 * A class representing the ES6 global lexical scope. 2742 */ 2743 private static class LexicalScope extends ScriptObject { 2744 2745 LexicalScope(final Global global) { 2746 super(global, PropertyMap.newMap()); 2747 } 2748 2749 @Override 2750 protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { 2751 return filterInvocation(super.findGetMethod(desc, request, operation)); 2752 } 2753 2754 @Override 2755 protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 2756 return filterInvocation(super.findSetMethod(desc, request)); 2757 } 2758 2759 @Override 2760 protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property, final boolean extensible) { 2761 // We override this method just to make it callable by Global 2762 return super.addBoundProperty(propMap, source, property, extensible); 2763 } 2764 2765 private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { 2766 final MethodType type = invocation.getInvocation().type(); 2767 return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); 2768 } 2769 } 2770 2771} 2772