/ jsc.cpp
jsc.cpp
1 /* 2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 3 * Copyright (C) 2004-2021 Apple Inc. All rights reserved. 4 * Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com) 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #include "config.h" 24 25 #include "ArrayBuffer.h" 26 #include "BigIntConstructor.h" 27 #include "BytecodeCacheError.h" 28 #include "CatchScope.h" 29 #include "CodeBlock.h" 30 #include "CodeCache.h" 31 #include "CompilerTimingScope.h" 32 #include "Completion.h" 33 #include "ConfigFile.h" 34 #include "DeferredWorkTimer.h" 35 #include "Disassembler.h" 36 #include "Exception.h" 37 #include "ExceptionHelpers.h" 38 #include "HeapSnapshotBuilder.h" 39 #include "InitializeThreading.h" 40 #include "Interpreter.h" 41 #include "JIT.h" 42 #include "JITOperationList.h" 43 #include "JSArray.h" 44 #include "JSArrayBuffer.h" 45 #include "JSBigInt.h" 46 #include "JSFinalizationRegistry.h" 47 #include "JSFunction.h" 48 #include "JSInternalPromise.h" 49 #include "JSLock.h" 50 #include "JSNativeStdFunction.h" 51 #include "JSONObject.h" 52 #include "JSObjectInlines.h" 53 #include "JSSourceCode.h" 54 #include "JSString.h" 55 #include "JSTypedArrays.h" 56 #include "JSWebAssemblyInstance.h" 57 #include "JSWebAssemblyMemory.h" 58 #include "LLIntThunks.h" 59 #include "ObjectConstructor.h" 60 #include "ParserError.h" 61 #include "ProfilerDatabase.h" 62 #include "ReleaseHeapAccessScope.h" 63 #include "SamplingProfiler.h" 64 #include "SimpleTypedArrayController.h" 65 #include "StackVisitor.h" 66 #include "StructureInlines.h" 67 #include "SuperSampler.h" 68 #include "TestRunnerUtils.h" 69 #include "TypedArrayInlines.h" 70 #include "VMInspector.h" 71 #include "WasmCapabilities.h" 72 #include "WasmFaultSignalHandler.h" 73 #include "WasmMemory.h" 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <sys/stat.h> 78 #include <sys/types.h> 79 #include <type_traits> 80 #include <wtf/CPUTime.h> 81 #include <wtf/FileSystem.h> 82 #include <wtf/MainThread.h> 83 #include <wtf/MemoryPressureHandler.h> 84 #include <wtf/MonotonicTime.h> 85 #include <wtf/Scope.h> 86 #include <wtf/StringPrintStream.h> 87 #include <wtf/URL.h> 88 #include <wtf/WallTime.h> 89 #include <wtf/text/StringBuilder.h> 90 #include <wtf/threads/Signals.h> 91 92 #if OS(WINDOWS) 93 #include <direct.h> 94 #include <fcntl.h> 95 #include <io.h> 96 #else 97 #include <unistd.h> 98 #endif 99 100 #if PLATFORM(COCOA) 101 #include <crt_externs.h> 102 #endif 103 104 #if PLATFORM(GTK) 105 #include <locale.h> 106 #endif 107 108 #if HAVE(READLINE) 109 // readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h 110 // We #define it to something else to avoid this conflict. 111 #define Function ReadlineFunction 112 #include <readline/history.h> 113 #include <readline/readline.h> 114 #undef Function 115 #endif 116 117 #if COMPILER(MSVC) 118 #include <crtdbg.h> 119 #include <mmsystem.h> 120 #include <windows.h> 121 #endif 122 123 #if OS(DARWIN) && CPU(ARM_THUMB2) 124 #include <fenv.h> 125 #include <arm/arch.h> 126 #endif 127 128 #if OS(DARWIN) 129 #include <wtf/spi/darwin/ProcessMemoryFootprint.h> 130 #elif OS(LINUX) 131 #include <wtf/linux/ProcessMemoryFootprint.h> 132 #endif 133 134 #if OS(DARWIN) || OS(LINUX) 135 struct MemoryFootprint : ProcessMemoryFootprint { 136 MemoryFootprint(const ProcessMemoryFootprint& src) 137 : ProcessMemoryFootprint(src) 138 { 139 } 140 }; 141 #else 142 struct MemoryFootprint { 143 uint64_t current; 144 uint64_t peak; 145 146 static MemoryFootprint now() 147 { 148 return { 0L, 0L }; 149 } 150 151 static void resetPeak() 152 { 153 } 154 }; 155 #endif 156 157 #if !defined(PATH_MAX) 158 #define PATH_MAX 4096 159 #endif 160 161 using namespace JSC; 162 163 namespace { 164 165 #define EXIT_EXCEPTION 3 166 167 NO_RETURN_WITH_VALUE static void jscExit(int status) 168 { 169 waitForAsynchronousDisassembly(); 170 171 #if ENABLE(DFG_JIT) 172 if (DFG::isCrashing()) { 173 for (;;) { 174 #if OS(WINDOWS) 175 Sleep(1000); 176 #else 177 pause(); 178 #endif 179 } 180 } 181 #endif // ENABLE(DFG_JIT) 182 exit(status); 183 } 184 185 static unsigned asyncTestPasses { 0 }; 186 static unsigned asyncTestExpectedPasses { 0 }; 187 188 } 189 190 template<typename Vector> 191 static bool fillBufferWithContentsOfFile(const String& fileName, Vector& buffer); 192 static RefPtr<Uint8Array> fillBufferWithContentsOfFile(const String& fileName); 193 194 class CommandLine; 195 class GlobalObject; 196 class Workers; 197 198 template<typename Func> 199 int runJSC(const CommandLine&, bool isWorker, const Func&); 200 static void checkException(GlobalObject*, bool isLastFile, bool hasException, JSValue, const CommandLine&, bool& success); 201 202 class Message : public ThreadSafeRefCounted<Message> { 203 public: 204 #if ENABLE(WEBASSEMBLY) 205 using Content = Variant<ArrayBufferContents, Ref<Wasm::MemoryHandle>>; 206 #else 207 using Content = Variant<ArrayBufferContents>; 208 #endif 209 Message(Content&&, int32_t); 210 ~Message(); 211 212 Content&& releaseContents() { return WTFMove(m_contents); } 213 int32_t index() const { return m_index; } 214 215 private: 216 Content m_contents; 217 int32_t m_index { 0 }; 218 }; 219 220 class Worker : public BasicRawSentinelNode<Worker> { 221 public: 222 Worker(Workers&); 223 ~Worker(); 224 225 void enqueue(const AbstractLocker&, RefPtr<Message>); 226 RefPtr<Message> dequeue(); 227 228 static Worker& current(); 229 230 private: 231 static ThreadSpecific<Worker*>& currentWorker(); 232 233 Workers& m_workers; 234 Deque<RefPtr<Message>> m_messages; 235 }; 236 237 class Workers { 238 WTF_MAKE_FAST_ALLOCATED; 239 WTF_MAKE_NONCOPYABLE(Workers); 240 public: 241 Workers(); 242 ~Workers(); 243 244 template<typename Func> 245 void broadcast(const Func&); 246 247 void report(const String&); 248 String tryGetReport(); 249 String getReport(); 250 251 static Workers& singleton(); 252 253 private: 254 friend class Worker; 255 256 Lock m_lock; 257 Condition m_condition; 258 SentinelLinkedList<Worker, BasicRawSentinelNode<Worker>> m_workers; 259 Deque<String> m_reports; 260 }; 261 262 263 static JSC_DECLARE_HOST_FUNCTION(functionCreateGlobalObject); 264 static JSC_DECLARE_HOST_FUNCTION(functionCreateHeapBigInt); 265 #if USE(BIGINT32) 266 static JSC_DECLARE_HOST_FUNCTION(functionCreateBigInt32); 267 #endif 268 static JSC_DECLARE_HOST_FUNCTION(functionUseBigInt32); 269 static JSC_DECLARE_HOST_FUNCTION(functionIsBigInt32); 270 static JSC_DECLARE_HOST_FUNCTION(functionIsHeapBigInt); 271 272 static JSC_DECLARE_HOST_FUNCTION(functionPrintStdOut); 273 static JSC_DECLARE_HOST_FUNCTION(functionPrintStdErr); 274 static JSC_DECLARE_HOST_FUNCTION(functionDebug); 275 static JSC_DECLARE_HOST_FUNCTION(functionDescribe); 276 static JSC_DECLARE_HOST_FUNCTION(functionDescribeArray); 277 static JSC_DECLARE_HOST_FUNCTION(functionSleepSeconds); 278 static JSC_DECLARE_HOST_FUNCTION(functionJSCStack); 279 static JSC_DECLARE_HOST_FUNCTION(functionGCAndSweep); 280 static JSC_DECLARE_HOST_FUNCTION(functionFullGC); 281 static JSC_DECLARE_HOST_FUNCTION(functionEdenGC); 282 static JSC_DECLARE_HOST_FUNCTION(functionHeapSize); 283 static JSC_DECLARE_HOST_FUNCTION(functionCreateMemoryFootprint); 284 static JSC_DECLARE_HOST_FUNCTION(functionResetMemoryPeak); 285 static JSC_DECLARE_HOST_FUNCTION(functionAddressOf); 286 static JSC_DECLARE_HOST_FUNCTION(functionVersion); 287 static JSC_DECLARE_HOST_FUNCTION(functionRun); 288 static JSC_DECLARE_HOST_FUNCTION(functionRunString); 289 static JSC_DECLARE_HOST_FUNCTION(functionLoad); 290 static JSC_DECLARE_HOST_FUNCTION(functionLoadString); 291 static JSC_DECLARE_HOST_FUNCTION(functionReadFile); 292 static JSC_DECLARE_HOST_FUNCTION(functionCheckSyntax); 293 static JSC_DECLARE_HOST_FUNCTION(functionReadline); 294 static JSC_DECLARE_HOST_FUNCTION(functionPreciseTime); 295 static JSC_DECLARE_HOST_FUNCTION(functionNeverInlineFunction); 296 static JSC_DECLARE_HOST_FUNCTION(functionNoDFG); 297 static JSC_DECLARE_HOST_FUNCTION(functionNoFTL); 298 static JSC_DECLARE_HOST_FUNCTION(functionNoOSRExitFuzzing); 299 static JSC_DECLARE_HOST_FUNCTION(functionOptimizeNextInvocation); 300 static JSC_DECLARE_HOST_FUNCTION(functionNumberOfDFGCompiles); 301 static JSC_DECLARE_HOST_FUNCTION(functionCallerIsOMGCompiled); 302 static JSC_DECLARE_HOST_FUNCTION(functionJSCOptions); 303 static JSC_DECLARE_HOST_FUNCTION(functionReoptimizationRetryCount); 304 static JSC_DECLARE_HOST_FUNCTION(functionTransferArrayBuffer); 305 static JSC_DECLARE_HOST_FUNCTION(functionFailNextNewCodeBlock); 306 static NO_RETURN_WITH_VALUE JSC_DECLARE_HOST_FUNCTION(functionQuit); 307 static JSC_DECLARE_HOST_FUNCTION(functionFalse); 308 static JSC_DECLARE_HOST_FUNCTION(functionUndefined1); 309 static JSC_DECLARE_HOST_FUNCTION(functionUndefined2); 310 static JSC_DECLARE_HOST_FUNCTION(functionIsInt32); 311 static JSC_DECLARE_HOST_FUNCTION(functionIsPureNaN); 312 static JSC_DECLARE_HOST_FUNCTION(functionEffectful42); 313 static JSC_DECLARE_HOST_FUNCTION(functionIdentity); 314 static JSC_DECLARE_HOST_FUNCTION(functionMakeMasquerader); 315 static JSC_DECLARE_HOST_FUNCTION(functionCallMasquerader); 316 static JSC_DECLARE_HOST_FUNCTION(functionHasCustomProperties); 317 static JSC_DECLARE_HOST_FUNCTION(functionDumpTypesForAllVariables); 318 static JSC_DECLARE_HOST_FUNCTION(functionDrainMicrotasks); 319 static JSC_DECLARE_HOST_FUNCTION(functionSetTimeout); 320 static JSC_DECLARE_HOST_FUNCTION(functionReleaseWeakRefs); 321 static JSC_DECLARE_HOST_FUNCTION(functionFinalizationRegistryLiveCount); 322 static JSC_DECLARE_HOST_FUNCTION(functionFinalizationRegistryDeadCount); 323 static JSC_DECLARE_HOST_FUNCTION(functionIs32BitPlatform); 324 static JSC_DECLARE_HOST_FUNCTION(functionCheckModuleSyntax); 325 static JSC_DECLARE_HOST_FUNCTION(functionPlatformSupportsSamplingProfiler); 326 static JSC_DECLARE_HOST_FUNCTION(functionGenerateHeapSnapshot); 327 static JSC_DECLARE_HOST_FUNCTION(functionGenerateHeapSnapshotForGCDebugging); 328 static JSC_DECLARE_HOST_FUNCTION(functionResetSuperSamplerState); 329 static JSC_DECLARE_HOST_FUNCTION(functionEnsureArrayStorage); 330 #if ENABLE(SAMPLING_PROFILER) 331 static JSC_DECLARE_HOST_FUNCTION(functionStartSamplingProfiler); 332 static JSC_DECLARE_HOST_FUNCTION(functionSamplingProfilerStackTraces); 333 #endif 334 335 static JSC_DECLARE_HOST_FUNCTION(functionMaxArguments); 336 static JSC_DECLARE_HOST_FUNCTION(functionAsyncTestStart); 337 static JSC_DECLARE_HOST_FUNCTION(functionAsyncTestPassed); 338 339 #if ENABLE(WEBASSEMBLY) 340 static JSC_DECLARE_HOST_FUNCTION(functionWebAssemblyMemoryMode); 341 #endif 342 343 #if ENABLE(SAMPLING_FLAGS) 344 static JSC_DECLARE_HOST_FUNCTION(functionSetSamplingFlags); 345 static JSC_DECLARE_HOST_FUNCTION(functionClearSamplingFlags); 346 #endif 347 348 static JSC_DECLARE_HOST_FUNCTION(functionGetRandomSeed); 349 static JSC_DECLARE_HOST_FUNCTION(functionSetRandomSeed); 350 static JSC_DECLARE_HOST_FUNCTION(functionIsRope); 351 static JSC_DECLARE_HOST_FUNCTION(functionCallerSourceOrigin); 352 static JSC_DECLARE_HOST_FUNCTION(functionDollarCreateRealm); 353 static JSC_DECLARE_HOST_FUNCTION(functionDollarEvalScript); 354 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentStart); 355 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentReceiveBroadcast); 356 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentReport); 357 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentSleep); 358 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentBroadcast); 359 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentGetReport); 360 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentLeaving); 361 static JSC_DECLARE_HOST_FUNCTION(functionDollarAgentMonotonicNow); 362 static JSC_DECLARE_HOST_FUNCTION(functionWaitForReport); 363 static JSC_DECLARE_HOST_FUNCTION(functionHeapCapacity); 364 static JSC_DECLARE_HOST_FUNCTION(functionFlashHeapAccess); 365 static JSC_DECLARE_HOST_FUNCTION(functionDisableRichSourceInfo); 366 static JSC_DECLARE_HOST_FUNCTION(functionMallocInALoop); 367 static JSC_DECLARE_HOST_FUNCTION(functionTotalCompileTime); 368 369 static JSC_DECLARE_HOST_FUNCTION(functionSetUnhandledRejectionCallback); 370 static JSC_DECLARE_HOST_FUNCTION(functionAsDoubleNumber); 371 372 static JSC_DECLARE_HOST_FUNCTION(functionDropAllLocks); 373 374 struct Script { 375 enum class StrictMode { 376 Strict, 377 Sloppy 378 }; 379 380 enum class ScriptType { 381 Script, 382 Module 383 }; 384 385 enum class CodeSource { 386 File, 387 CommandLine 388 }; 389 390 StrictMode strictMode; 391 CodeSource codeSource; 392 ScriptType scriptType; 393 char* argument; 394 395 Script(StrictMode strictMode, CodeSource codeSource, ScriptType scriptType, char *argument) 396 : strictMode(strictMode) 397 , codeSource(codeSource) 398 , scriptType(scriptType) 399 , argument(argument) 400 { 401 if (strictMode == StrictMode::Strict) 402 ASSERT(codeSource == CodeSource::File); 403 } 404 }; 405 406 class CommandLine { 407 public: 408 CommandLine(int argc, char** argv) 409 { 410 parseArguments(argc, argv); 411 } 412 413 enum CommandLineForWorkersTag { CommandLineForWorkers }; 414 CommandLine(CommandLineForWorkersTag) 415 { 416 } 417 418 Vector<Script> m_scripts; 419 Vector<String> m_arguments; 420 String m_profilerOutput; 421 String m_uncaughtExceptionName; 422 bool m_interactive { false }; 423 bool m_dump { false }; 424 bool m_module { false }; 425 bool m_exitCode { false }; 426 bool m_destroyVM { false }; 427 bool m_profile { false }; 428 bool m_treatWatchdogExceptionAsSuccess { false }; 429 bool m_alwaysDumpUncaughtException { false }; 430 bool m_dumpMemoryFootprint { false }; 431 bool m_dumpSamplingProfilerData { false }; 432 bool m_enableRemoteDebugging { false }; 433 bool m_canBlockIsFalse { false }; 434 435 void parseArguments(int, char**); 436 }; 437 438 static const char interactivePrompt[] = ">>> "; 439 440 class StopWatch { 441 public: 442 void start(); 443 void stop(); 444 long getElapsedMS(); // call stop() first 445 446 private: 447 MonotonicTime m_startTime; 448 MonotonicTime m_stopTime; 449 }; 450 451 void StopWatch::start() 452 { 453 m_startTime = MonotonicTime::now(); 454 } 455 456 void StopWatch::stop() 457 { 458 m_stopTime = MonotonicTime::now(); 459 } 460 461 long StopWatch::getElapsedMS() 462 { 463 return (m_stopTime - m_startTime).millisecondsAs<long>(); 464 } 465 466 template<typename Vector> 467 static inline String stringFromUTF(const Vector& utf8) 468 { 469 return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size()); 470 } 471 472 static JSC_DECLARE_CUSTOM_GETTER(accessorMakeMasquerader); 473 static JSC_DECLARE_CUSTOM_SETTER(testCustomAccessorSetter); 474 static JSC_DECLARE_CUSTOM_SETTER(testCustomValueSetter); 475 476 JSC_DEFINE_CUSTOM_GETTER(accessorMakeMasquerader, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName)) 477 { 478 VM& vm = globalObject->vm(); 479 return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, "IsHTMLDDA"_s, functionCallMasquerader)); 480 } 481 482 483 class GlobalObject final : public JSGlobalObject { 484 public: 485 using Base = JSGlobalObject; 486 487 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments) 488 { 489 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure); 490 object->finishCreation(vm, arguments); 491 return object; 492 } 493 494 DECLARE_INFO; 495 static const GlobalObjectMethodTable s_globalObjectMethodTable; 496 497 static Structure* createStructure(VM& vm, JSValue prototype) 498 { 499 return Structure::create(vm, nullptr, prototype, TypeInfo(GlobalObjectType, StructureFlags), info()); 500 } 501 502 static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags::createAllEnabled(); } 503 504 private: 505 GlobalObject(VM&, Structure*); 506 507 static constexpr unsigned DontEnum = 0 | PropertyAttribute::DontEnum; 508 509 void finishCreation(VM& vm, const Vector<String>& arguments) 510 { 511 Base::finishCreation(vm); 512 JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); 513 514 addFunction(vm, "debug", functionDebug, 1); 515 addFunction(vm, "describe", functionDescribe, 1); 516 addFunction(vm, "describeArray", functionDescribeArray, 1); 517 addFunction(vm, "print", functionPrintStdOut, 1); 518 addFunction(vm, "printErr", functionPrintStdErr, 1); 519 addFunction(vm, "quit", functionQuit, 0); 520 addFunction(vm, "gc", functionGCAndSweep, 0); 521 addFunction(vm, "fullGC", functionFullGC, 0); 522 addFunction(vm, "edenGC", functionEdenGC, 0); 523 addFunction(vm, "gcHeapSize", functionHeapSize, 0); 524 addFunction(vm, "MemoryFootprint", functionCreateMemoryFootprint, 0); 525 addFunction(vm, "resetMemoryPeak", functionResetMemoryPeak, 0); 526 addFunction(vm, "addressOf", functionAddressOf, 1); 527 addFunction(vm, "version", functionVersion, 1); 528 addFunction(vm, "run", functionRun, 1); 529 addFunction(vm, "runString", functionRunString, 1); 530 addFunction(vm, "load", functionLoad, 1); 531 addFunction(vm, "loadString", functionLoadString, 1); 532 addFunction(vm, "readFile", functionReadFile, 2); 533 addFunction(vm, "read", functionReadFile, 2); 534 addFunction(vm, "checkSyntax", functionCheckSyntax, 1); 535 addFunction(vm, "sleepSeconds", functionSleepSeconds, 1); 536 addFunction(vm, "jscStack", functionJSCStack, 1); 537 addFunction(vm, "readline", functionReadline, 0); 538 addFunction(vm, "preciseTime", functionPreciseTime, 0); 539 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1); 540 addFunction(vm, "noInline", functionNeverInlineFunction, 1); 541 addFunction(vm, "noDFG", functionNoDFG, 1); 542 addFunction(vm, "noFTL", functionNoFTL, 1); 543 addFunction(vm, "noOSRExitFuzzing", functionNoOSRExitFuzzing, 1); 544 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1); 545 addFunction(vm, "callerIsOMGCompiled", functionCallerIsOMGCompiled, 0); 546 addFunction(vm, "jscOptions", functionJSCOptions, 0); 547 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1); 548 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1); 549 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1); 550 addFunction(vm, "failNextNewCodeBlock", functionFailNextNewCodeBlock, 1); 551 #if ENABLE(SAMPLING_FLAGS) 552 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1); 553 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1); 554 #endif 555 556 putDirectNativeFunction(vm, this, Identifier::fromString(vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum); 557 putDirectNativeFunction(vm, this, Identifier::fromString(vm, "isFinalTier"), 0, functionFalse, IsFinalTierIntrinsic, DontEnum); 558 putDirectNativeFunction(vm, this, Identifier::fromString(vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum); 559 putDirectNativeFunction(vm, this, Identifier::fromString(vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, DontEnum); 560 putDirectNativeFunction(vm, this, Identifier::fromString(vm, "isPureNaN"), 0, functionIsPureNaN, CheckInt32Intrinsic, DontEnum); 561 putDirectNativeFunction(vm, this, Identifier::fromString(vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum); 562 563 addFunction(vm, "effectful42", functionEffectful42, 0); 564 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0); 565 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0); 566 567 addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0); 568 addFunction(vm, "createHeapBigInt", functionCreateHeapBigInt, 1); 569 #if USE(BIGINT32) 570 addFunction(vm, "createBigInt32", functionCreateBigInt32, 1); 571 #endif 572 addFunction(vm, "useBigInt32", functionUseBigInt32, 0); 573 addFunction(vm, "isBigInt32", functionIsBigInt32, 1); 574 addFunction(vm, "isHeapBigInt", functionIsHeapBigInt, 1); 575 576 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0); 577 578 addFunction(vm, "drainMicrotasks", functionDrainMicrotasks, 0); 579 addFunction(vm, "setTimeout", functionSetTimeout, 2); 580 581 addFunction(vm, "releaseWeakRefs", functionReleaseWeakRefs, 0); 582 addFunction(vm, "finalizationRegistryLiveCount", functionFinalizationRegistryLiveCount, 0); 583 addFunction(vm, "finalizationRegistryDeadCount", functionFinalizationRegistryDeadCount, 0); 584 585 addFunction(vm, "getRandomSeed", functionGetRandomSeed, 0); 586 addFunction(vm, "setRandomSeed", functionSetRandomSeed, 1); 587 addFunction(vm, "isRope", functionIsRope, 1); 588 addFunction(vm, "callerSourceOrigin", functionCallerSourceOrigin, 0); 589 590 addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0); 591 592 addFunction(vm, "checkModuleSyntax", functionCheckModuleSyntax, 1); 593 594 addFunction(vm, "platformSupportsSamplingProfiler", functionPlatformSupportsSamplingProfiler, 0); 595 addFunction(vm, "generateHeapSnapshot", functionGenerateHeapSnapshot, 0); 596 addFunction(vm, "generateHeapSnapshotForGCDebugging", functionGenerateHeapSnapshotForGCDebugging, 0); 597 addFunction(vm, "resetSuperSamplerState", functionResetSuperSamplerState, 0); 598 addFunction(vm, "ensureArrayStorage", functionEnsureArrayStorage, 0); 599 #if ENABLE(SAMPLING_PROFILER) 600 addFunction(vm, "startSamplingProfiler", functionStartSamplingProfiler, 0); 601 addFunction(vm, "samplingProfilerStackTraces", functionSamplingProfilerStackTraces, 0); 602 #endif 603 604 addFunction(vm, "maxArguments", functionMaxArguments, 0); 605 606 addFunction(vm, "asyncTestStart", functionAsyncTestStart, 1); 607 addFunction(vm, "asyncTestPassed", functionAsyncTestPassed, 1); 608 609 #if ENABLE(WEBASSEMBLY) 610 addFunction(vm, "WebAssemblyMemoryMode", functionWebAssemblyMemoryMode, 1); 611 #endif 612 613 if (!arguments.isEmpty()) { 614 JSArray* array = constructEmptyArray(this, nullptr); 615 for (size_t i = 0; i < arguments.size(); ++i) 616 array->putDirectIndex(this, i, jsString(vm, arguments[i])); 617 putDirect(vm, Identifier::fromString(vm, "arguments"), array, DontEnum); 618 } 619 620 putDirect(vm, Identifier::fromString(vm, "console"), jsUndefined(), DontEnum); 621 622 Structure* plainObjectStructure = JSFinalObject::createStructure(vm, this, objectPrototype(), 0); 623 624 JSObject* dollar = JSFinalObject::create(vm, plainObjectStructure); 625 putDirect(vm, Identifier::fromString(vm, "$"), dollar, DontEnum); 626 putDirect(vm, Identifier::fromString(vm, "$262"), dollar, DontEnum); 627 628 addFunction(vm, dollar, "createRealm", functionDollarCreateRealm, 0); 629 addFunction(vm, dollar, "detachArrayBuffer", functionTransferArrayBuffer, 1); 630 addFunction(vm, dollar, "evalScript", functionDollarEvalScript, 1); 631 632 dollar->putDirect(vm, Identifier::fromString(vm, "global"), this, DontEnum); 633 dollar->putDirectCustomAccessor(vm, Identifier::fromString(vm, "IsHTMLDDA"), 634 CustomGetterSetter::create(vm, accessorMakeMasquerader, nullptr), 635 static_cast<unsigned>(PropertyAttribute::CustomValue) 636 ); 637 638 JSObject* agent = JSFinalObject::create(vm, plainObjectStructure); 639 dollar->putDirect(vm, Identifier::fromString(vm, "agent"), agent, DontEnum); 640 641 // The test262 INTERPRETING.md document says that some of these functions are just in the main 642 // thread and some are in the other threads. We just put them in all threads. 643 addFunction(vm, agent, "start", functionDollarAgentStart, 1); 644 addFunction(vm, agent, "receiveBroadcast", functionDollarAgentReceiveBroadcast, 1); 645 addFunction(vm, agent, "report", functionDollarAgentReport, 1); 646 addFunction(vm, agent, "sleep", functionDollarAgentSleep, 1); 647 addFunction(vm, agent, "broadcast", functionDollarAgentBroadcast, 1); 648 addFunction(vm, agent, "getReport", functionDollarAgentGetReport, 0); 649 addFunction(vm, agent, "leaving", functionDollarAgentLeaving, 0); 650 addFunction(vm, agent, "monotonicNow", functionDollarAgentMonotonicNow, 0); 651 652 addFunction(vm, "waitForReport", functionWaitForReport, 0); 653 654 addFunction(vm, "heapCapacity", functionHeapCapacity, 0); 655 addFunction(vm, "flashHeapAccess", functionFlashHeapAccess, 0); 656 657 addFunction(vm, "disableRichSourceInfo", functionDisableRichSourceInfo, 0); 658 addFunction(vm, "mallocInALoop", functionMallocInALoop, 0); 659 addFunction(vm, "totalCompileTime", functionTotalCompileTime, 0); 660 661 addFunction(vm, "setUnhandledRejectionCallback", functionSetUnhandledRejectionCallback, 1); 662 663 addFunction(vm, "asDoubleNumber", functionAsDoubleNumber, 1); 664 665 addFunction(vm, "dropAllLocks", functionDropAllLocks, 1); 666 667 if (Options::exposeCustomSettersOnGlobalObjectForTesting()) { 668 { 669 CustomGetterSetter* custom = CustomGetterSetter::create(vm, nullptr, testCustomAccessorSetter); 670 Identifier identifier = Identifier::fromString(vm, "testCustomAccessorSetter"); 671 this->putDirectCustomAccessor(vm, identifier, custom, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::CustomAccessor); 672 } 673 674 { 675 CustomGetterSetter* custom = CustomGetterSetter::create(vm, nullptr, testCustomValueSetter); 676 Identifier identifier = Identifier::fromString(vm, "testCustomValueSetter"); 677 this->putDirectCustomAccessor(vm, identifier, custom, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::CustomValue); 678 } 679 } 680 } 681 682 public: 683 static bool testCustomSetterImpl(JSGlobalObject* lexicalGlobalObject, GlobalObject* thisObject, EncodedJSValue encodedValue, const char* propertyName) 684 { 685 VM& vm = lexicalGlobalObject->vm(); 686 687 Identifier identifier = Identifier::fromString(vm, propertyName); 688 thisObject->putDirect(vm, identifier, JSValue::decode(encodedValue), DontEnum); 689 690 return true; 691 } 692 693 private: 694 void addFunction(VM& vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments) 695 { 696 Identifier identifier = Identifier::fromString(vm, name); 697 object->putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function), DontEnum); 698 } 699 700 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments) 701 { 702 addFunction(vm, this, name, function, arguments); 703 } 704 705 static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, JSModuleLoader*, JSString*, JSValue, const SourceOrigin&); 706 static Identifier moduleLoaderResolve(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, JSValue); 707 static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, JSValue); 708 static JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, JSModuleLoader*, JSValue, JSModuleRecord*, JSValue); 709 710 static void reportUncaughtExceptionAtEventLoop(JSGlobalObject*, Exception*); 711 }; 712 STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(GlobalObject, JSGlobalObject); 713 714 static bool supportsRichSourceInfo = true; 715 static bool shellSupportsRichSourceInfo(const JSGlobalObject*) 716 { 717 return supportsRichSourceInfo; 718 } 719 720 const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(GlobalObject) }; 721 const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { 722 &shellSupportsRichSourceInfo, 723 &shouldInterruptScript, 724 &javaScriptRuntimeFlags, 725 nullptr, // queueTaskToEventLoop 726 &shouldInterruptScriptBeforeTimeout, 727 &moduleLoaderImportModule, 728 &moduleLoaderResolve, 729 &moduleLoaderFetch, 730 &moduleLoaderCreateImportMetaProperties, 731 nullptr, // moduleLoaderEvaluate 732 nullptr, // promiseRejectionTracker 733 &reportUncaughtExceptionAtEventLoop, 734 ¤tScriptExecutionOwner, 735 &scriptExecutionStatus, 736 nullptr, // defaultLanguage 737 nullptr, // compileStreaming 738 nullptr, // instantinateStreaming 739 }; 740 741 GlobalObject::GlobalObject(VM& vm, Structure* structure) 742 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable) 743 { 744 } 745 746 JSC_DEFINE_CUSTOM_SETTER(testCustomAccessorSetter, (JSGlobalObject* lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue)) 747 { 748 VM& vm = lexicalGlobalObject->vm(); 749 RELEASE_ASSERT(JSValue::decode(thisValue).isCell()); 750 JSCell* thisCell = JSValue::decode(thisValue).asCell(); 751 RELEASE_ASSERT(thisCell->type() == PureForwardingProxyType); 752 GlobalObject* thisObject = jsDynamicCast<GlobalObject*>(vm, jsCast<JSProxy*>(thisCell)->target()); 753 RELEASE_ASSERT(thisObject); 754 return GlobalObject::testCustomSetterImpl(lexicalGlobalObject, thisObject, encodedValue, "_testCustomAccessorSetter"); 755 } 756 757 JSC_DEFINE_CUSTOM_SETTER(testCustomValueSetter, (JSGlobalObject* lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue)) 758 { 759 VM& vm = lexicalGlobalObject->vm(); 760 RELEASE_ASSERT(JSValue::decode(thisValue).isCell()); 761 JSCell* thisCell = JSValue::decode(thisValue).asCell(); 762 GlobalObject* thisObject = jsDynamicCast<GlobalObject*>(vm, thisCell); 763 RELEASE_ASSERT(thisObject); 764 return GlobalObject::testCustomSetterImpl(lexicalGlobalObject, thisObject, encodedValue, "_testCustomValueSetter"); 765 } 766 767 static UChar pathSeparator() 768 { 769 #if OS(WINDOWS) 770 return '\\'; 771 #else 772 return '/'; 773 #endif 774 } 775 776 static URL currentWorkingDirectory() 777 { 778 #if OS(WINDOWS) 779 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364934.aspx 780 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath 781 // The _MAX_PATH in Windows is 260. If the path of the current working directory is longer than that, _getcwd truncates the result. 782 // And other I/O functions taking a path name also truncate it. To avoid this situation, 783 // 784 // (1). When opening the file in Windows for modules, we always use the abosolute path and add "\\?\" prefix to the path name. 785 // (2). When retrieving the current working directory, use GetCurrentDirectory instead of _getcwd. 786 // 787 // In the path utility functions inside the JSC shell, we does not handle the UNC and UNCW including the network host name. 788 DWORD bufferLength = ::GetCurrentDirectoryW(0, nullptr); 789 if (!bufferLength) 790 return { }; 791 // In Windows, wchar_t is the UTF-16LE. 792 // https://msdn.microsoft.com/en-us/library/dd374081.aspx 793 // https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407.aspx 794 Vector<wchar_t> buffer(bufferLength); 795 DWORD lengthNotIncludingNull = ::GetCurrentDirectoryW(bufferLength, buffer.data()); 796 String directoryString(buffer.data(), lengthNotIncludingNull); 797 // We don't support network path like \\host\share\<path name>. 798 if (directoryString.startsWith("\\\\")) 799 return { }; 800 801 #else 802 Vector<char> buffer(PATH_MAX); 803 if (!getcwd(buffer.data(), PATH_MAX)) 804 return { }; 805 String directoryString = String::fromUTF8(buffer.data()); 806 #endif 807 if (directoryString.isEmpty()) 808 return { }; 809 810 // Add a trailing slash if needed so the URL resolves to a directory and not a file. 811 if (directoryString[directoryString.length() - 1] != pathSeparator()) 812 directoryString = makeString(directoryString, pathSeparator()); 813 814 return URL::fileURLWithFileSystemPath(directoryString); 815 } 816 817 static URL absolutePath(const String& fileName) 818 { 819 auto directoryName = currentWorkingDirectory(); 820 if (!directoryName.isValid()) 821 return URL::fileURLWithFileSystemPath(fileName); 822 823 return URL(directoryName, fileName); 824 } 825 826 JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject* globalObject, JSModuleLoader*, JSString* moduleNameValue, JSValue parameters, const SourceOrigin& sourceOrigin) 827 { 828 VM& vm = globalObject->vm(); 829 auto throwScope = DECLARE_THROW_SCOPE(vm); 830 831 auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); 832 833 auto catchScope = DECLARE_CATCH_SCOPE(vm); 834 835 auto rejectWithError = [&](JSValue error) { 836 promise->reject(globalObject, error); 837 return promise; 838 }; 839 840 auto reject = [&](Exception* exception) { 841 if (UNLIKELY(isTerminatedExecutionException(vm, exception))) 842 return promise; 843 JSValue error = exception->value(); 844 catchScope.clearException(); 845 return rejectWithError(error); 846 }; 847 848 auto referrer = sourceOrigin.url(); 849 auto specifier = moduleNameValue->value(globalObject); 850 RETURN_IF_EXCEPTION(throwScope, nullptr); 851 if (UNLIKELY(catchScope.exception())) 852 return reject(catchScope.exception()); 853 854 if (!referrer.isLocalFile()) 855 return rejectWithError(createError(globalObject, makeString("Could not resolve the referrer's path '", referrer.string(), "', while trying to resolve module '", specifier, "'."))); 856 857 if (!specifier.startsWith('/') && !specifier.startsWith("./") && !specifier.startsWith("../")) 858 return rejectWithError(createTypeError(globalObject, makeString("Module specifier, '"_s, specifier, "' does not start with \"/\", \"./\", or \"../\". Referenced from: "_s, referrer.fileSystemPath()))); 859 860 URL moduleURL(referrer, specifier); 861 if (!moduleURL.isLocalFile()) 862 return rejectWithError(createError(globalObject, makeString("Module url, '", moduleURL.string(), "' does not map to a local file."))); 863 864 auto result = JSC::importModule(globalObject, Identifier::fromString(vm, moduleURL.string()), parameters, jsUndefined()); 865 if (UNLIKELY(catchScope.exception())) 866 return reject(catchScope.exception()); 867 return result; 868 } 869 870 Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue) 871 { 872 VM& vm = globalObject->vm(); 873 auto scope = DECLARE_THROW_SCOPE(vm); 874 875 scope.releaseAssertNoException(); 876 const Identifier key = keyValue.toPropertyKey(globalObject); 877 RETURN_IF_EXCEPTION(scope, { }); 878 879 if (key.isSymbol()) 880 return key; 881 882 auto resolvePath = [&] (const URL& directoryURL) -> Identifier { 883 String specifier = key.impl(); 884 if (!specifier.startsWith('/') && !specifier.startsWith("./") && !specifier.startsWith("../")) { 885 throwTypeError(globalObject, scope, makeString("Module specifier, '"_s, specifier, "' does not start with \"/\", \"./\", or \"../\". Referenced from: "_s, directoryURL.fileSystemPath())); 886 return { }; 887 } 888 889 if (!directoryURL.isLocalFile()) { 890 throwException(globalObject, scope, createError(globalObject, makeString("Could not resolve the referrer's path: ", directoryURL.string()))); 891 return { }; 892 } 893 894 URL resolvedURL(directoryURL, specifier); 895 if (!resolvedURL.isValid()) { 896 throwException(globalObject, scope, createError(globalObject, makeString("Resolved module url is not valid: ", resolvedURL.string()))); 897 return { }; 898 } 899 ASSERT(resolvedURL.isLocalFile()); 900 901 return Identifier::fromString(vm, resolvedURL.string()); 902 }; 903 904 if (referrerValue.isUndefined()) 905 return resolvePath(currentWorkingDirectory()); 906 907 const Identifier referrer = referrerValue.toPropertyKey(globalObject); 908 RETURN_IF_EXCEPTION(scope, { }); 909 910 if (referrer.isSymbol()) 911 return resolvePath(currentWorkingDirectory()); 912 913 // If the referrer exists, we assume that the referrer is the correct file url. 914 URL url = URL({ }, referrer.impl()); 915 ASSERT(url.isLocalFile()); 916 return resolvePath(url); 917 } 918 919 template<typename Vector> 920 static void convertShebangToJSComment(Vector& buffer) 921 { 922 if (buffer.size() >= 2) { 923 if (buffer[0] == '#' && buffer[1] == '!') 924 buffer[0] = buffer[1] = '/'; 925 } 926 } 927 928 static RefPtr<Uint8Array> fillBufferWithContentsOfFile(FILE* file) 929 { 930 if (fseek(file, 0, SEEK_END) == -1) 931 return nullptr; 932 long bufferCapacity = ftell(file); 933 if (bufferCapacity == -1) 934 return nullptr; 935 if (fseek(file, 0, SEEK_SET) == -1) 936 return nullptr; 937 auto result = Uint8Array::tryCreate(bufferCapacity); 938 if (!result) 939 return nullptr; 940 size_t readSize = fread(result->data(), 1, bufferCapacity, file); 941 if (readSize != static_cast<size_t>(bufferCapacity)) 942 return nullptr; 943 return result; 944 } 945 946 static RefPtr<Uint8Array> fillBufferWithContentsOfFile(const String& fileName) 947 { 948 FILE* f = fopen(fileName.utf8().data(), "rb"); 949 if (!f) { 950 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data()); 951 return nullptr; 952 } 953 954 RefPtr<Uint8Array> result = fillBufferWithContentsOfFile(f); 955 fclose(f); 956 957 return result; 958 } 959 960 template<typename Vector> 961 static bool fillBufferWithContentsOfFile(FILE* file, Vector& buffer) 962 { 963 // We might have injected "use strict"; at the top. 964 size_t initialSize = buffer.size(); 965 if (fseek(file, 0, SEEK_END) == -1) 966 return false; 967 long bufferCapacity = ftell(file); 968 if (bufferCapacity == -1) 969 return false; 970 if (fseek(file, 0, SEEK_SET) == -1) 971 return false; 972 buffer.resize(bufferCapacity + initialSize); 973 size_t readSize = fread(buffer.data() + initialSize, 1, buffer.size(), file); 974 return readSize == buffer.size() - initialSize; 975 } 976 977 static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer) 978 { 979 FILE* f = fopen(fileName.utf8().data(), "rb"); 980 if (!f) { 981 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data()); 982 return false; 983 } 984 985 bool result = fillBufferWithContentsOfFile(f, buffer); 986 fclose(f); 987 988 return result; 989 } 990 991 static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>& buffer) 992 { 993 if (!fillBufferWithContentsOfFile(fileName, buffer)) 994 return false; 995 convertShebangToJSComment(buffer); 996 return true; 997 } 998 999 class ShellSourceProvider final : public StringSourceProvider { 1000 public: 1001 static Ref<ShellSourceProvider> create(const String& source, const SourceOrigin& sourceOrigin, String&& sourceURL, const TextPosition& startPosition, SourceProviderSourceType sourceType) 1002 { 1003 return adoptRef(*new ShellSourceProvider(source, sourceOrigin, WTFMove(sourceURL), startPosition, sourceType)); 1004 } 1005 1006 ~ShellSourceProvider() final 1007 { 1008 commitCachedBytecode(); 1009 } 1010 1011 RefPtr<CachedBytecode> cachedBytecode() const final 1012 { 1013 if (!m_cachedBytecode) 1014 loadBytecode(); 1015 return m_cachedBytecode.copyRef(); 1016 } 1017 1018 void updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode&, CodeSpecializationKind kind, const UnlinkedFunctionCodeBlock* codeBlock) const final 1019 { 1020 if (!cacheEnabled() || !m_cachedBytecode) 1021 return; 1022 BytecodeCacheError error; 1023 RefPtr<CachedBytecode> cachedBytecode = encodeFunctionCodeBlock(executable->vm(), codeBlock, error); 1024 if (cachedBytecode && !error.isValid()) 1025 m_cachedBytecode->addFunctionUpdate(executable, kind, *cachedBytecode); 1026 } 1027 1028 void cacheBytecode(const BytecodeCacheGenerator& generator) const final 1029 { 1030 if (!cacheEnabled()) 1031 return; 1032 if (!m_cachedBytecode) 1033 m_cachedBytecode = CachedBytecode::create(); 1034 auto update = generator(); 1035 if (update) 1036 m_cachedBytecode->addGlobalUpdate(*update); 1037 } 1038 1039 void commitCachedBytecode() const final 1040 { 1041 if (!cacheEnabled() || !m_cachedBytecode || !m_cachedBytecode->hasUpdates()) 1042 return; 1043 1044 auto clearBytecode = makeScopeExit([&] { 1045 m_cachedBytecode = nullptr; 1046 }); 1047 1048 String filename = cachePath(); 1049 auto fd = FileSystem::openAndLockFile(filename, FileSystem::FileOpenMode::Write, {FileSystem::FileLockMode::Exclusive, FileSystem::FileLockMode::Nonblocking}); 1050 if (!FileSystem::isHandleValid(fd)) 1051 return; 1052 1053 auto closeFD = makeScopeExit([&] { 1054 FileSystem::unlockAndCloseFile(fd); 1055 }); 1056 1057 long long fileSize; 1058 if (!FileSystem::getFileSize(fd, fileSize)) 1059 return; 1060 1061 size_t cacheFileSize; 1062 if (!WTF::convertSafely(fileSize, cacheFileSize) || cacheFileSize != m_cachedBytecode->size()) { 1063 // The bytecode cache has already been updated 1064 return; 1065 } 1066 1067 if (!FileSystem::truncateFile(fd, m_cachedBytecode->sizeForUpdate())) 1068 return; 1069 1070 m_cachedBytecode->commitUpdates([&] (off_t offset, const void* data, size_t size) { 1071 long long result = FileSystem::seekFile(fd, offset, FileSystem::FileSeekOrigin::Beginning); 1072 ASSERT_UNUSED(result, result != -1); 1073 size_t bytesWritten = static_cast<size_t>(FileSystem::writeToFile(fd, static_cast<const char*>(data), size)); 1074 ASSERT_UNUSED(bytesWritten, bytesWritten == size); 1075 }); 1076 } 1077 1078 private: 1079 String cachePath() const 1080 { 1081 if (!cacheEnabled()) 1082 return static_cast<const char*>(nullptr); 1083 const char* cachePath = Options::diskCachePath(); 1084 String filename = FileSystem::encodeForFileName(FileSystem::lastComponentOfPathIgnoringTrailingSlash(sourceOrigin().url().fileSystemPath())); 1085 return FileSystem::pathByAppendingComponent(cachePath, makeString(source().toString().hash(), '-', filename, ".bytecode-cache")); 1086 } 1087 1088 void loadBytecode() const 1089 { 1090 if (!cacheEnabled()) 1091 return; 1092 1093 String filename = cachePath(); 1094 if (filename.isNull()) 1095 return; 1096 1097 auto fd = FileSystem::openAndLockFile(filename, FileSystem::FileOpenMode::Read, {FileSystem::FileLockMode::Shared, FileSystem::FileLockMode::Nonblocking}); 1098 if (!FileSystem::isHandleValid(fd)) 1099 return; 1100 1101 auto closeFD = makeScopeExit([&] { 1102 FileSystem::unlockAndCloseFile(fd); 1103 }); 1104 1105 bool success; 1106 FileSystem::MappedFileData mappedFileData(fd, FileSystem::MappedFileMode::Private, success); 1107 1108 if (!success) 1109 return; 1110 1111 m_cachedBytecode = CachedBytecode::create(WTFMove(mappedFileData)); 1112 } 1113 1114 ShellSourceProvider(const String& source, const SourceOrigin& sourceOrigin, String&& sourceURL, const TextPosition& startPosition, SourceProviderSourceType sourceType) 1115 : StringSourceProvider(source, sourceOrigin, WTFMove(sourceURL), startPosition, sourceType) 1116 { 1117 } 1118 1119 static bool cacheEnabled() 1120 { 1121 static bool enabled = !!Options::diskCachePath(); 1122 return enabled; 1123 } 1124 1125 mutable RefPtr<CachedBytecode> m_cachedBytecode; 1126 }; 1127 1128 static inline SourceCode jscSource(const String& source, const SourceOrigin& sourceOrigin, String sourceURL = String(), const TextPosition& startPosition = TextPosition(), SourceProviderSourceType sourceType = SourceProviderSourceType::Program) 1129 { 1130 return SourceCode(ShellSourceProvider::create(source, sourceOrigin, WTFMove(sourceURL), startPosition, sourceType), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt()); 1131 } 1132 1133 template<typename Vector> 1134 static inline SourceCode jscSource(const Vector& utf8, const SourceOrigin& sourceOrigin, const String& filename) 1135 { 1136 // FIXME: This should use an absolute file URL https://bugs.webkit.org/show_bug.cgi?id=193077 1137 String str = stringFromUTF(utf8); 1138 return jscSource(str, sourceOrigin, filename); 1139 } 1140 1141 template<typename Vector> 1142 static bool fetchModuleFromLocalFileSystem(const URL& fileURL, Vector& buffer) 1143 { 1144 String fileName = fileURL.fileSystemPath(); 1145 #if OS(WINDOWS) 1146 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath 1147 // Use long UNC to pass the long path name to the Windows APIs. 1148 auto pathName = makeString("\\\\?\\", fileName).wideCharacters(); 1149 struct _stat status { }; 1150 if (_wstat(pathName.data(), &status)) 1151 return false; 1152 if ((status.st_mode & S_IFMT) != S_IFREG) 1153 return false; 1154 1155 FILE* f = _wfopen(pathName.data(), L"rb"); 1156 #else 1157 auto pathName = fileName.utf8(); 1158 struct stat status { }; 1159 if (stat(pathName.data(), &status)) 1160 return false; 1161 if ((status.st_mode & S_IFMT) != S_IFREG) 1162 return false; 1163 1164 FILE* f = fopen(pathName.data(), "r"); 1165 #endif 1166 if (!f) { 1167 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data()); 1168 return false; 1169 } 1170 1171 bool result = fillBufferWithContentsOfFile(f, buffer); 1172 if (result) 1173 convertShebangToJSComment(buffer); 1174 fclose(f); 1175 1176 return result; 1177 } 1178 1179 JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, JSModuleLoader*, JSValue key, JSValue, JSValue) 1180 { 1181 VM& vm = globalObject->vm(); 1182 JSInternalPromise* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); 1183 1184 auto catchScope = DECLARE_CATCH_SCOPE(vm); 1185 1186 auto rejectWithError = [&](JSValue error) { 1187 promise->reject(globalObject, error); 1188 return promise; 1189 }; 1190 1191 auto reject = [&](Exception* exception) { 1192 if (UNLIKELY(isTerminatedExecutionException(vm, exception))) 1193 return promise; 1194 JSValue error = exception->value(); 1195 catchScope.clearException(); 1196 return rejectWithError(error); 1197 }; 1198 1199 String moduleKey = key.toWTFString(globalObject); 1200 if (UNLIKELY(catchScope.exception())) 1201 return reject(catchScope.exception()); 1202 1203 URL moduleURL({ }, moduleKey); 1204 ASSERT(moduleURL.isLocalFile()); 1205 // Strip the URI from our key so Errors print canonical system paths. 1206 moduleKey = moduleURL.fileSystemPath(); 1207 1208 Vector<uint8_t> buffer; 1209 if (!fetchModuleFromLocalFileSystem(moduleURL, buffer)) 1210 return rejectWithError(createError(globalObject, makeString("Could not open file '", moduleKey, "'."))); 1211 1212 #if ENABLE(WEBASSEMBLY) 1213 // FileSystem does not have mime-type header. The JSC shell recognizes WebAssembly's magic header. 1214 if (buffer.size() >= 4) { 1215 if (buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' && buffer[3] == 'm') { 1216 auto source = SourceCode(WebAssemblySourceProvider::create(WTFMove(buffer), SourceOrigin { moduleURL }, WTFMove(moduleKey))); 1217 catchScope.releaseAssertNoException(); 1218 auto sourceCode = JSSourceCode::create(vm, WTFMove(source)); 1219 catchScope.releaseAssertNoException(); 1220 promise->resolve(globalObject, sourceCode); 1221 return promise; 1222 } 1223 } 1224 #endif 1225 1226 auto sourceCode = JSSourceCode::create(vm, jscSource(stringFromUTF(buffer), SourceOrigin { moduleURL }, WTFMove(moduleKey), TextPosition(), SourceProviderSourceType::Module)); 1227 catchScope.releaseAssertNoException(); 1228 promise->resolve(globalObject, sourceCode); 1229 return promise; 1230 } 1231 1232 JSObject* GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObject* globalObject, JSModuleLoader*, JSValue key, JSModuleRecord*, JSValue) 1233 { 1234 VM& vm = globalObject->vm(); 1235 auto scope = DECLARE_THROW_SCOPE(vm); 1236 1237 JSObject* metaProperties = constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()); 1238 RETURN_IF_EXCEPTION(scope, nullptr); 1239 1240 metaProperties->putDirect(vm, Identifier::fromString(vm, "filename"), key); 1241 RETURN_IF_EXCEPTION(scope, nullptr); 1242 1243 return metaProperties; 1244 } 1245 1246 static CString cStringFromViewWithString(JSGlobalObject* globalObject, ThrowScope& scope, StringViewWithUnderlyingString& viewWithString) 1247 { 1248 Expected<CString, UTF8ConversionError> expectedString = viewWithString.view.tryGetUtf8(); 1249 if (expectedString) 1250 return expectedString.value(); 1251 switch (expectedString.error()) { 1252 case UTF8ConversionError::OutOfMemory: 1253 throwOutOfMemoryError(globalObject, scope); 1254 break; 1255 case UTF8ConversionError::IllegalSource: 1256 scope.throwException(globalObject, createError(globalObject, "Illegal source encountered during UTF8 conversion")); 1257 break; 1258 case UTF8ConversionError::SourceExhausted: 1259 scope.throwException(globalObject, createError(globalObject, "Source exhausted during UTF8 conversion")); 1260 break; 1261 default: 1262 RELEASE_ASSERT_NOT_REACHED(); 1263 } 1264 return { }; 1265 } 1266 1267 static EncodedJSValue printInternal(JSGlobalObject* globalObject, CallFrame* callFrame, FILE* out) 1268 { 1269 VM& vm = globalObject->vm(); 1270 auto scope = DECLARE_THROW_SCOPE(vm); 1271 1272 if (asyncTestExpectedPasses) { 1273 JSValue value = callFrame->argument(0); 1274 if (value.isString() && WTF::equal(asString(value)->value(globalObject).impl(), "Test262:AsyncTestComplete")) { 1275 asyncTestPasses++; 1276 return JSValue::encode(jsUndefined()); 1277 } 1278 } 1279 1280 for (unsigned i = 0; i < callFrame->argumentCount(); ++i) { 1281 if (i) 1282 if (EOF == fputc(' ', out)) 1283 goto fail; 1284 1285 auto* jsString = callFrame->uncheckedArgument(i).toString(globalObject); 1286 RETURN_IF_EXCEPTION(scope, { }); 1287 auto viewWithString = jsString->viewWithUnderlyingString(globalObject); 1288 RETURN_IF_EXCEPTION(scope, { }); 1289 auto string = cStringFromViewWithString(globalObject, scope, viewWithString); 1290 RETURN_IF_EXCEPTION(scope, { }); 1291 fwrite(string.data(), sizeof(char), string.length(), out); 1292 if (ferror(out)) 1293 goto fail; 1294 } 1295 1296 fputc('\n', out); 1297 fail: 1298 fflush(out); 1299 return JSValue::encode(jsUndefined()); 1300 } 1301 1302 JSC_DEFINE_HOST_FUNCTION(functionPrintStdOut, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1303 { 1304 return printInternal(globalObject, callFrame, stdout); 1305 } 1306 1307 JSC_DEFINE_HOST_FUNCTION(functionPrintStdErr, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1308 { 1309 return printInternal(globalObject, callFrame, stderr); 1310 } 1311 1312 JSC_DEFINE_HOST_FUNCTION(functionDebug, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1313 { 1314 VM& vm = globalObject->vm(); 1315 auto scope = DECLARE_THROW_SCOPE(vm); 1316 auto* jsString = callFrame->argument(0).toString(globalObject); 1317 RETURN_IF_EXCEPTION(scope, { }); 1318 auto viewWithString = jsString->viewWithUnderlyingString(globalObject); 1319 RETURN_IF_EXCEPTION(scope, { }); 1320 auto string = cStringFromViewWithString(globalObject, scope, viewWithString); 1321 RETURN_IF_EXCEPTION(scope, { }); 1322 fputs("--> ", stderr); 1323 fwrite(string.data(), sizeof(char), string.length(), stderr); 1324 fputc('\n', stderr); 1325 return JSValue::encode(jsUndefined()); 1326 } 1327 1328 JSC_DEFINE_HOST_FUNCTION(functionDescribe, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1329 { 1330 VM& vm = globalObject->vm(); 1331 if (callFrame->argumentCount() < 1) 1332 return JSValue::encode(jsUndefined()); 1333 return JSValue::encode(jsString(vm, toString(callFrame->argument(0)))); 1334 } 1335 1336 JSC_DEFINE_HOST_FUNCTION(functionDescribeArray, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1337 { 1338 if (callFrame->argumentCount() < 1) 1339 return JSValue::encode(jsUndefined()); 1340 VM& vm = globalObject->vm(); 1341 JSObject* object = jsDynamicCast<JSObject*>(vm, callFrame->argument(0)); 1342 if (!object) 1343 return JSValue::encode(jsNontrivialString(vm, "<not object>"_s)); 1344 return JSValue::encode(jsNontrivialString(vm, toString("<Butterfly: ", RawPointer(object->butterfly()), "; public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">"))); 1345 } 1346 1347 JSC_DEFINE_HOST_FUNCTION(functionSleepSeconds, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1348 { 1349 VM& vm = globalObject->vm(); 1350 auto scope = DECLARE_THROW_SCOPE(vm); 1351 1352 if (callFrame->argumentCount() >= 1) { 1353 Seconds seconds = Seconds(callFrame->argument(0).toNumber(globalObject)); 1354 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1355 sleep(seconds); 1356 } 1357 1358 return JSValue::encode(jsUndefined()); 1359 } 1360 1361 class FunctionJSCStackFunctor { 1362 public: 1363 FunctionJSCStackFunctor(StringBuilder& trace) 1364 : m_trace(trace) 1365 { 1366 } 1367 1368 StackVisitor::Status operator()(StackVisitor& visitor) const 1369 { 1370 m_trace.append(makeString(" ", visitor->index(), " ", visitor->toString(), '\n')); 1371 return StackVisitor::Continue; 1372 } 1373 1374 private: 1375 StringBuilder& m_trace; 1376 }; 1377 1378 JSC_DEFINE_HOST_FUNCTION(functionJSCStack, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1379 { 1380 VM& vm = globalObject->vm(); 1381 StringBuilder trace; 1382 trace.appendLiteral("--> Stack trace:\n"); 1383 1384 FunctionJSCStackFunctor functor(trace); 1385 callFrame->iterate(vm, functor); 1386 fprintf(stderr, "%s", trace.toString().utf8().data()); 1387 return JSValue::encode(jsUndefined()); 1388 } 1389 1390 JSC_DEFINE_HOST_FUNCTION(functionGCAndSweep, (JSGlobalObject* globalObject, CallFrame*)) 1391 { 1392 VM& vm = globalObject->vm(); 1393 JSLockHolder lock(vm); 1394 vm.heap.collectNow(Sync, CollectionScope::Full); 1395 return JSValue::encode(jsNumber(vm.heap.sizeAfterLastFullCollection())); 1396 } 1397 1398 JSC_DEFINE_HOST_FUNCTION(functionFullGC, (JSGlobalObject* globalObject, CallFrame*)) 1399 { 1400 VM& vm = globalObject->vm(); 1401 JSLockHolder lock(vm); 1402 vm.heap.collectSync(CollectionScope::Full); 1403 return JSValue::encode(jsNumber(vm.heap.sizeAfterLastFullCollection())); 1404 } 1405 1406 JSC_DEFINE_HOST_FUNCTION(functionEdenGC, (JSGlobalObject* globalObject, CallFrame*)) 1407 { 1408 VM& vm = globalObject->vm(); 1409 JSLockHolder lock(vm); 1410 vm.heap.collectSync(CollectionScope::Eden); 1411 return JSValue::encode(jsNumber(vm.heap.sizeAfterLastEdenCollection())); 1412 } 1413 1414 JSC_DEFINE_HOST_FUNCTION(functionHeapSize, (JSGlobalObject* globalObject, CallFrame*)) 1415 { 1416 VM& vm = globalObject->vm(); 1417 JSLockHolder lock(vm); 1418 return JSValue::encode(jsNumber(vm.heap.size())); 1419 } 1420 1421 class JSCMemoryFootprint : public JSDestructibleObject { 1422 using Base = JSDestructibleObject; 1423 public: 1424 template<typename CellType, SubspaceAccess> 1425 static CompleteSubspace* subspaceFor(VM& vm) 1426 { 1427 return &vm.destructibleObjectSpace; 1428 } 1429 1430 JSCMemoryFootprint(VM& vm, Structure* structure) 1431 : Base(vm, structure) 1432 { } 1433 1434 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 1435 { 1436 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); 1437 } 1438 1439 static JSCMemoryFootprint* create(VM& vm, JSGlobalObject* globalObject) 1440 { 1441 Structure* structure = createStructure(vm, globalObject, jsNull()); 1442 JSCMemoryFootprint* footprint = new (NotNull, allocateCell<JSCMemoryFootprint>(vm.heap)) JSCMemoryFootprint(vm, structure); 1443 footprint->finishCreation(vm); 1444 return footprint; 1445 } 1446 1447 void finishCreation(VM& vm) 1448 { 1449 Base::finishCreation(vm); 1450 1451 auto addProperty = [&] (VM& vm, const char* name, JSValue value) { 1452 JSCMemoryFootprint::addProperty(vm, name, value); 1453 }; 1454 1455 MemoryFootprint footprint = MemoryFootprint::now(); 1456 1457 addProperty(vm, "current", jsNumber(footprint.current)); 1458 addProperty(vm, "peak", jsNumber(footprint.peak)); 1459 } 1460 1461 DECLARE_INFO; 1462 1463 private: 1464 void addProperty(VM& vm, const char* name, JSValue value) 1465 { 1466 Identifier identifier = Identifier::fromString(vm, name); 1467 putDirect(vm, identifier, value); 1468 } 1469 }; 1470 1471 const ClassInfo JSCMemoryFootprint::s_info = { "MemoryFootprint", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCMemoryFootprint) }; 1472 1473 JSC_DEFINE_HOST_FUNCTION(functionCreateMemoryFootprint, (JSGlobalObject* globalObject, CallFrame*)) 1474 { 1475 VM& vm = globalObject->vm(); 1476 JSLockHolder lock(vm); 1477 return JSValue::encode(JSCMemoryFootprint::create(vm, globalObject)); 1478 } 1479 1480 JSC_DEFINE_HOST_FUNCTION(functionResetMemoryPeak, (JSGlobalObject*, CallFrame*)) 1481 { 1482 MemoryFootprint::resetPeak(); 1483 return JSValue::encode(jsUndefined()); 1484 } 1485 1486 // This function is not generally very helpful in 64-bit code as the tag and payload 1487 // share a register. But in 32-bit JITed code the tag may not be checked if an 1488 // optimization removes type checking requirements, such as in ===. 1489 JSC_DEFINE_HOST_FUNCTION(functionAddressOf, (JSGlobalObject*, CallFrame* callFrame)) 1490 { 1491 JSValue value = callFrame->argument(0); 1492 if (!value.isCell()) 1493 return JSValue::encode(jsUndefined()); 1494 // Need to cast to uint64_t so bitwise_cast will play along. 1495 uint64_t asNumber = reinterpret_cast<uint64_t>(value.asCell()); 1496 EncodedJSValue returnValue = JSValue::encode(jsNumber(bitwise_cast<double>(asNumber))); 1497 return returnValue; 1498 } 1499 1500 JSC_DEFINE_HOST_FUNCTION(functionVersion, (JSGlobalObject*, CallFrame*)) 1501 { 1502 // We need this function for compatibility with the Mozilla JS tests but for now 1503 // we don't actually do any version-specific handling 1504 return JSValue::encode(jsUndefined()); 1505 } 1506 1507 JSC_DEFINE_HOST_FUNCTION(functionRun, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1508 { 1509 VM& vm = globalObject->vm(); 1510 auto scope = DECLARE_THROW_SCOPE(vm); 1511 1512 String fileName = callFrame->argument(0).toWTFString(globalObject); 1513 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1514 Vector<char> script; 1515 if (!fetchScriptFromLocalFileSystem(fileName, script)) 1516 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Could not open file."_s))); 1517 1518 GlobalObject* realm = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>()); 1519 1520 JSArray* array = constructEmptyArray(realm, nullptr); 1521 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1522 for (unsigned i = 1; i < callFrame->argumentCount(); ++i) { 1523 array->putDirectIndex(realm, i - 1, callFrame->uncheckedArgument(i)); 1524 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1525 } 1526 realm->putDirect(vm, Identifier::fromString(vm, "arguments"), array); 1527 1528 NakedPtr<Exception> exception; 1529 StopWatch stopWatch; 1530 stopWatch.start(); 1531 evaluate(realm, jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), exception); 1532 stopWatch.stop(); 1533 1534 if (exception) { 1535 throwException(realm, scope, exception); 1536 return JSValue::encode(jsUndefined()); 1537 } 1538 1539 return JSValue::encode(jsNumber(stopWatch.getElapsedMS())); 1540 } 1541 1542 JSC_DEFINE_HOST_FUNCTION(functionRunString, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1543 { 1544 VM& vm = globalObject->vm(); 1545 auto scope = DECLARE_THROW_SCOPE(vm); 1546 1547 String source = callFrame->argument(0).toWTFString(globalObject); 1548 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1549 1550 GlobalObject* realm = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>()); 1551 1552 JSArray* array = constructEmptyArray(realm, nullptr); 1553 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1554 for (unsigned i = 1; i < callFrame->argumentCount(); ++i) { 1555 array->putDirectIndex(realm, i - 1, callFrame->uncheckedArgument(i)); 1556 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1557 } 1558 realm->putDirect(vm, Identifier::fromString(vm, "arguments"), array); 1559 1560 NakedPtr<Exception> exception; 1561 evaluate(realm, jscSource(source, callFrame->callerSourceOrigin(vm)), JSValue(), exception); 1562 1563 if (exception) { 1564 scope.throwException(realm, exception); 1565 return JSValue::encode(jsUndefined()); 1566 } 1567 1568 return JSValue::encode(realm); 1569 } 1570 1571 JSC_DEFINE_HOST_FUNCTION(functionLoad, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1572 { 1573 VM& vm = globalObject->vm(); 1574 auto scope = DECLARE_THROW_SCOPE(vm); 1575 1576 bool callerRelative = callFrame->argument(1).getString(globalObject) == "caller relative"_s; 1577 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1578 1579 String fileName = callFrame->argument(0).toWTFString(globalObject); 1580 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1581 1582 URL path; 1583 if (callerRelative) { 1584 path = URL(callFrame->callerSourceOrigin(vm).url(), fileName); 1585 if (!path.isLocalFile()) 1586 return throwVMException(globalObject, scope, createURIError(globalObject, makeString("caller relative URL path is not a local file: ", path.string()))); 1587 } else 1588 path = absolutePath(fileName); 1589 Vector<char> script; 1590 if (!fetchScriptFromLocalFileSystem(path.fileSystemPath(), script)) 1591 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Could not open file."_s))); 1592 1593 NakedPtr<Exception> evaluationException; 1594 JSValue result = evaluate(globalObject, jscSource(script, SourceOrigin { path }, fileName), JSValue(), evaluationException); 1595 if (evaluationException) 1596 throwException(globalObject, scope, evaluationException); 1597 return JSValue::encode(result); 1598 } 1599 1600 JSC_DEFINE_HOST_FUNCTION(functionLoadString, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1601 { 1602 VM& vm = globalObject->vm(); 1603 auto scope = DECLARE_THROW_SCOPE(vm); 1604 1605 String sourceCode = callFrame->argument(0).toWTFString(globalObject); 1606 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1607 1608 NakedPtr<Exception> evaluationException; 1609 JSValue result = evaluate(globalObject, jscSource(sourceCode, callFrame->callerSourceOrigin(vm)), JSValue(), evaluationException); 1610 if (evaluationException) 1611 throwException(globalObject, scope, evaluationException); 1612 return JSValue::encode(result); 1613 } 1614 1615 JSC_DEFINE_HOST_FUNCTION(functionReadFile, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1616 { 1617 VM& vm = globalObject->vm(); 1618 auto scope = DECLARE_THROW_SCOPE(vm); 1619 1620 String fileName = callFrame->argument(0).toWTFString(globalObject); 1621 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1622 1623 bool isBinary = false; 1624 if (callFrame->argumentCount() > 1) { 1625 String type = callFrame->argument(1).toWTFString(globalObject); 1626 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1627 if (type != "binary") 1628 return throwVMError(globalObject, scope, "Expected 'binary' as second argument."); 1629 isBinary = true; 1630 } 1631 1632 RefPtr<Uint8Array> content = fillBufferWithContentsOfFile(fileName); 1633 if (!content) 1634 return throwVMError(globalObject, scope, "Could not open file."); 1635 1636 if (!isBinary) 1637 return JSValue::encode(jsString(vm, String::fromUTF8WithLatin1Fallback(content->data(), content->length()))); 1638 1639 Structure* structure = globalObject->typedArrayStructure(TypeUint8); 1640 JSObject* result = JSUint8Array::create(vm, structure, WTFMove(content)); 1641 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1642 1643 return JSValue::encode(result); 1644 } 1645 1646 JSC_DEFINE_HOST_FUNCTION(functionCheckSyntax, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1647 { 1648 VM& vm = globalObject->vm(); 1649 auto scope = DECLARE_THROW_SCOPE(vm); 1650 1651 String fileName = callFrame->argument(0).toWTFString(globalObject); 1652 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1653 Vector<char> script; 1654 if (!fetchScriptFromLocalFileSystem(fileName, script)) 1655 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Could not open file."_s))); 1656 1657 StopWatch stopWatch; 1658 stopWatch.start(); 1659 1660 JSValue syntaxException; 1661 bool validSyntax = checkSyntax(globalObject, jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), &syntaxException); 1662 stopWatch.stop(); 1663 1664 if (!validSyntax) 1665 throwException(globalObject, scope, syntaxException); 1666 return JSValue::encode(jsNumber(stopWatch.getElapsedMS())); 1667 } 1668 1669 #if ENABLE(SAMPLING_FLAGS) 1670 JSC_DEFINE_HOST_FUNCTION(functionSetSamplingFlags, (JSGlobalObject*, CallFrame* callFrame)) 1671 { 1672 for (unsigned i = 0; i < callFrame->argumentCount(); ++i) { 1673 unsigned flag = static_cast<unsigned>(callFrame->uncheckedArgument(i).toNumber(globalObject)); 1674 if ((flag >= 1) && (flag <= 32)) 1675 SamplingFlags::setFlag(flag); 1676 } 1677 return JSValue::encode(jsNull()); 1678 } 1679 1680 JSC_DEFINE_HOST_FUNCTION(functionClearSamplingFlags, (JSGlobalObject*, CallFrame* callFrame)) 1681 { 1682 for (unsigned i = 0; i < callFrame->argumentCount(); ++i) { 1683 unsigned flag = static_cast<unsigned>(callFrame->uncheckedArgument(i).toNumber(globalObject)); 1684 if ((flag >= 1) && (flag <= 32)) 1685 SamplingFlags::clearFlag(flag); 1686 } 1687 return JSValue::encode(jsNull()); 1688 } 1689 #endif 1690 1691 JSC_DEFINE_HOST_FUNCTION(functionGetRandomSeed, (JSGlobalObject* globalObject, CallFrame*)) 1692 { 1693 return JSValue::encode(jsNumber(globalObject->weakRandom().seed())); 1694 } 1695 1696 JSC_DEFINE_HOST_FUNCTION(functionSetRandomSeed, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1697 { 1698 VM& vm = globalObject->vm(); 1699 auto scope = DECLARE_THROW_SCOPE(vm); 1700 1701 unsigned seed = callFrame->argument(0).toUInt32(globalObject); 1702 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1703 globalObject->weakRandom().setSeed(seed); 1704 return JSValue::encode(jsUndefined()); 1705 } 1706 1707 JSC_DEFINE_HOST_FUNCTION(functionIsRope, (JSGlobalObject*, CallFrame* callFrame)) 1708 { 1709 JSValue argument = callFrame->argument(0); 1710 if (!argument.isString()) 1711 return JSValue::encode(jsBoolean(false)); 1712 const StringImpl* impl = asString(argument)->tryGetValueImpl(); 1713 return JSValue::encode(jsBoolean(!impl)); 1714 } 1715 1716 JSC_DEFINE_HOST_FUNCTION(functionCallerSourceOrigin, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1717 { 1718 VM& vm = globalObject->vm(); 1719 SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); 1720 if (sourceOrigin.url().isNull()) 1721 return JSValue::encode(jsNull()); 1722 return JSValue::encode(jsString(vm, sourceOrigin.string())); 1723 } 1724 1725 JSC_DEFINE_HOST_FUNCTION(functionReadline, (JSGlobalObject* globalObject, CallFrame*)) 1726 { 1727 Vector<char, 256> line; 1728 int c; 1729 while ((c = getchar()) != EOF) { 1730 // FIXME: Should we also break on \r? 1731 if (c == '\n') 1732 break; 1733 line.append(c); 1734 } 1735 line.append('\0'); 1736 return JSValue::encode(jsString(globalObject->vm(), line.data())); 1737 } 1738 1739 JSC_DEFINE_HOST_FUNCTION(functionPreciseTime, (JSGlobalObject*, CallFrame*)) 1740 { 1741 return JSValue::encode(jsNumber(WallTime::now().secondsSinceEpoch().value())); 1742 } 1743 1744 JSC_DEFINE_HOST_FUNCTION(functionNeverInlineFunction, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1745 { 1746 return JSValue::encode(setNeverInline(globalObject, callFrame)); 1747 } 1748 1749 JSC_DEFINE_HOST_FUNCTION(functionNoDFG, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1750 { 1751 return JSValue::encode(setNeverOptimize(globalObject, callFrame)); 1752 } 1753 1754 JSC_DEFINE_HOST_FUNCTION(functionNoFTL, (JSGlobalObject*, CallFrame* callFrame)) 1755 { 1756 if (callFrame->argumentCount()) { 1757 FunctionExecutable* executable = getExecutableForFunction(callFrame->argument(0)); 1758 if (executable) 1759 executable->setNeverFTLOptimize(true); 1760 } 1761 return JSValue::encode(jsUndefined()); 1762 } 1763 1764 JSC_DEFINE_HOST_FUNCTION(functionNoOSRExitFuzzing, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1765 { 1766 return JSValue::encode(setCannotUseOSRExitFuzzing(globalObject, callFrame)); 1767 } 1768 1769 JSC_DEFINE_HOST_FUNCTION(functionOptimizeNextInvocation, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1770 { 1771 return JSValue::encode(optimizeNextInvocation(globalObject, callFrame)); 1772 } 1773 1774 JSC_DEFINE_HOST_FUNCTION(functionNumberOfDFGCompiles, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1775 { 1776 return JSValue::encode(numberOfDFGCompiles(globalObject, callFrame)); 1777 } 1778 1779 JSC_DEFINE_HOST_FUNCTION(functionCallerIsOMGCompiled, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1780 { 1781 VM& vm = globalObject->vm(); 1782 auto scope = DECLARE_THROW_SCOPE(vm); 1783 1784 if (!Options::useBBQTierUpChecks()) 1785 return JSValue::encode(jsBoolean(true)); 1786 1787 CallerFunctor wasmToJSFrame; 1788 StackVisitor::visit(callFrame, vm, wasmToJSFrame); 1789 if (!wasmToJSFrame.callerFrame()->isAnyWasmCallee()) 1790 return throwVMError(globalObject, scope, "caller is not a wasm->js import function"); 1791 1792 // We have a wrapper frame that we generate for imports. If we ever can direct call from wasm we would need to change this. 1793 ASSERT(!wasmToJSFrame.callerFrame()->callee().isWasm()); 1794 CallerFunctor wasmFrame; 1795 StackVisitor::visit(wasmToJSFrame.callerFrame(), vm, wasmFrame); 1796 ASSERT(wasmFrame.callerFrame()->callee().isWasm()); 1797 #if ENABLE(WEBASSEMBLY) 1798 auto mode = wasmFrame.callerFrame()->callee().asWasmCallee()->compilationMode(); 1799 return JSValue::encode(jsBoolean(mode == Wasm::CompilationMode::OMGMode || mode == Wasm::CompilationMode::OMGForOSREntryMode)); 1800 #endif 1801 RELEASE_ASSERT_NOT_REACHED(); 1802 } 1803 1804 Message::Message(Content&& contents, int32_t index) 1805 : m_contents(WTFMove(contents)) 1806 , m_index(index) 1807 { 1808 } 1809 1810 Message::~Message() 1811 { 1812 } 1813 1814 Worker::Worker(Workers& workers) 1815 : m_workers(workers) 1816 { 1817 auto locker = holdLock(m_workers.m_lock); 1818 m_workers.m_workers.append(this); 1819 1820 *currentWorker() = this; 1821 } 1822 1823 Worker::~Worker() 1824 { 1825 auto locker = holdLock(m_workers.m_lock); 1826 RELEASE_ASSERT(isOnList()); 1827 remove(); 1828 } 1829 1830 void Worker::enqueue(const AbstractLocker&, RefPtr<Message> message) 1831 { 1832 m_messages.append(message); 1833 } 1834 1835 RefPtr<Message> Worker::dequeue() 1836 { 1837 auto locker = holdLock(m_workers.m_lock); 1838 while (m_messages.isEmpty()) 1839 m_workers.m_condition.wait(m_workers.m_lock); 1840 return m_messages.takeFirst(); 1841 } 1842 1843 Worker& Worker::current() 1844 { 1845 return **currentWorker(); 1846 } 1847 1848 ThreadSpecific<Worker*>& Worker::currentWorker() 1849 { 1850 static ThreadSpecific<Worker*>* result; 1851 static std::once_flag flag; 1852 std::call_once( 1853 flag, 1854 [] () { 1855 result = new ThreadSpecific<Worker*>(); 1856 }); 1857 return *result; 1858 } 1859 1860 Workers::Workers() 1861 { 1862 } 1863 1864 Workers::~Workers() 1865 { 1866 UNREACHABLE_FOR_PLATFORM(); 1867 } 1868 1869 template<typename Func> 1870 void Workers::broadcast(const Func& func) 1871 { 1872 auto locker = holdLock(m_lock); 1873 for (Worker* worker = m_workers.begin(); worker != m_workers.end(); worker = worker->next()) { 1874 if (worker != &Worker::current()) 1875 func(locker, *worker); 1876 } 1877 m_condition.notifyAll(); 1878 } 1879 1880 void Workers::report(const String& string) 1881 { 1882 auto locker = holdLock(m_lock); 1883 m_reports.append(string.isolatedCopy()); 1884 m_condition.notifyAll(); 1885 } 1886 1887 String Workers::tryGetReport() 1888 { 1889 auto locker = holdLock(m_lock); 1890 if (m_reports.isEmpty()) 1891 return String(); 1892 return m_reports.takeFirst(); 1893 } 1894 1895 String Workers::getReport() 1896 { 1897 auto locker = holdLock(m_lock); 1898 while (m_reports.isEmpty()) 1899 m_condition.wait(m_lock); 1900 return m_reports.takeFirst(); 1901 } 1902 1903 Workers& Workers::singleton() 1904 { 1905 static Workers* result; 1906 static std::once_flag flag; 1907 std::call_once( 1908 flag, 1909 [] { 1910 result = new Workers(); 1911 }); 1912 return *result; 1913 } 1914 1915 JSC_DEFINE_HOST_FUNCTION(functionDollarCreateRealm, (JSGlobalObject* globalObject, CallFrame*)) 1916 { 1917 VM& vm = globalObject->vm(); 1918 GlobalObject* result = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>()); 1919 return JSValue::encode(result->getDirect(vm, Identifier::fromString(vm, "$"))); 1920 } 1921 1922 JSC_DEFINE_HOST_FUNCTION(functionDollarEvalScript, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1923 { 1924 VM& vm = globalObject->vm(); 1925 auto scope = DECLARE_THROW_SCOPE(vm); 1926 1927 String sourceCode = callFrame->argument(0).toWTFString(globalObject); 1928 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1929 1930 JSValue global = callFrame->thisValue().get(globalObject, Identifier::fromString(vm, "global")); 1931 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1932 GlobalObject* realm = jsDynamicCast<GlobalObject*>(vm, global); 1933 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1934 if (!realm) 1935 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Expected global to point to a global object"_s))); 1936 1937 NakedPtr<Exception> evaluationException; 1938 JSValue result = evaluate(realm, jscSource(sourceCode, callFrame->callerSourceOrigin(vm)), JSValue(), evaluationException); 1939 if (evaluationException) 1940 throwException(globalObject, scope, evaluationException); 1941 return JSValue::encode(result); 1942 } 1943 1944 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentStart, (JSGlobalObject* globalObject, CallFrame* callFrame)) 1945 { 1946 VM& vm = globalObject->vm(); 1947 auto scope = DECLARE_THROW_SCOPE(vm); 1948 1949 String sourceCode = callFrame->argument(0).toWTFString(globalObject); 1950 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1951 1952 Lock didStartLock; 1953 Condition didStartCondition; 1954 bool didStart = false; 1955 1956 auto isGigacageMemoryExhausted = [&](Gigacage::Kind kind) { 1957 if (!Gigacage::isEnabled(kind)) 1958 return false; 1959 if (Gigacage::footprint(kind) < Gigacage::size(kind) * 0.8) 1960 return false; 1961 return true; 1962 }; 1963 1964 if (isGigacageMemoryExhausted(Gigacage::JSValue) || isGigacageMemoryExhausted(Gigacage::Primitive)) 1965 return JSValue::encode(throwOutOfMemoryError(globalObject, scope, "Gigacage is exhausted"_s)); 1966 1967 String workerPath = "worker"_s; 1968 if (!callFrame->argument(1).isUndefined()) { 1969 workerPath = callFrame->argument(1).toWTFString(globalObject); 1970 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1971 } 1972 1973 Thread::create( 1974 "JSC Agent", 1975 [sourceCode = sourceCode.isolatedCopy(), workerPath = workerPath.isolatedCopy(), &didStartLock, &didStartCondition, &didStart] () { 1976 CommandLine commandLine(CommandLine::CommandLineForWorkers); 1977 commandLine.m_interactive = false; 1978 runJSC( 1979 commandLine, true, 1980 [&] (VM&, GlobalObject* globalObject, bool& success) { 1981 // Notify the thread that started us that we have registered a worker. 1982 { 1983 auto locker = holdLock(didStartLock); 1984 didStart = true; 1985 didStartCondition.notifyOne(); 1986 } 1987 1988 NakedPtr<Exception> evaluationException; 1989 JSValue result; 1990 result = evaluate(globalObject, jscSource(sourceCode, SourceOrigin(URL({ }, workerPath))), JSValue(), evaluationException); 1991 if (evaluationException) 1992 result = evaluationException->value(); 1993 checkException(globalObject, true, evaluationException, result, commandLine, success); 1994 if (!success) 1995 exit(1); 1996 }); 1997 })->detach(); 1998 1999 { 2000 auto locker = holdLock(didStartLock); 2001 while (!didStart) 2002 didStartCondition.wait(didStartLock); 2003 } 2004 2005 return JSValue::encode(jsUndefined()); 2006 } 2007 2008 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentReceiveBroadcast, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2009 { 2010 VM& vm = globalObject->vm(); 2011 auto scope = DECLARE_THROW_SCOPE(vm); 2012 2013 JSValue callback = callFrame->argument(0); 2014 auto callData = getCallData(vm, callback); 2015 if (callData.type == CallData::Type::None) 2016 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Expected callback"_s))); 2017 2018 RefPtr<Message> message; 2019 { 2020 ReleaseHeapAccessScope releaseAccess(vm.heap); 2021 message = Worker::current().dequeue(); 2022 } 2023 2024 auto content = message->releaseContents(); 2025 JSValue result = ([&]() -> JSValue { 2026 if (WTF::holds_alternative<ArrayBufferContents>(content)) { 2027 auto nativeBuffer = ArrayBuffer::create(WTF::get<ArrayBufferContents>(WTFMove(content))); 2028 ArrayBufferSharingMode sharingMode = nativeBuffer->sharingMode(); 2029 return JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(sharingMode), WTFMove(nativeBuffer)); 2030 } 2031 #if ENABLE(WEBASSEMBLY) 2032 if (WTF::holds_alternative<Ref<Wasm::MemoryHandle>>(content)) { 2033 JSWebAssemblyMemory* jsMemory = JSC::JSWebAssemblyMemory::tryCreate(globalObject, vm, globalObject->webAssemblyMemoryStructure()); 2034 scope.releaseAssertNoException(); 2035 Ref<Wasm::Memory> memory = Wasm::Memory::create(WTF::get<Ref<Wasm::MemoryHandle>>(WTFMove(content)), 2036 [&vm] (Wasm::Memory::NotifyPressure) { vm.heap.collectAsync(CollectionScope::Full); }, 2037 [&vm] (Wasm::Memory::SyncTryToReclaim) { vm.heap.collectSync(CollectionScope::Full); }, 2038 [&vm, jsMemory] (Wasm::Memory::GrowSuccess, Wasm::PageCount oldPageCount, Wasm::PageCount newPageCount) { jsMemory->growSuccessCallback(vm, oldPageCount, newPageCount); }); 2039 jsMemory->adopt(WTFMove(memory)); 2040 return jsMemory; 2041 } 2042 #endif 2043 return jsUndefined(); 2044 })(); 2045 2046 MarkedArgumentBuffer args; 2047 args.append(result); 2048 args.append(jsNumber(message->index())); 2049 if (UNLIKELY(args.hasOverflowed())) 2050 return JSValue::encode(throwOutOfMemoryError(globalObject, scope)); 2051 RELEASE_AND_RETURN(scope, JSValue::encode(call(globalObject, callback, callData, jsNull(), args))); 2052 } 2053 2054 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentReport, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2055 { 2056 VM& vm = globalObject->vm(); 2057 auto scope = DECLARE_THROW_SCOPE(vm); 2058 2059 String report = callFrame->argument(0).toWTFString(globalObject); 2060 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2061 2062 Workers::singleton().report(report); 2063 2064 return JSValue::encode(jsUndefined()); 2065 } 2066 2067 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentSleep, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2068 { 2069 VM& vm = globalObject->vm(); 2070 auto scope = DECLARE_THROW_SCOPE(vm); 2071 2072 if (callFrame->argumentCount() >= 1) { 2073 Seconds seconds = Seconds::fromMilliseconds(callFrame->argument(0).toNumber(globalObject)); 2074 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2075 sleep(seconds); 2076 } 2077 return JSValue::encode(jsUndefined()); 2078 } 2079 2080 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentBroadcast, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2081 { 2082 VM& vm = globalObject->vm(); 2083 auto scope = DECLARE_THROW_SCOPE(vm); 2084 2085 int32_t index = callFrame->argument(1).toInt32(globalObject); 2086 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2087 2088 JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(vm, callFrame->argument(0)); 2089 if (jsBuffer && jsBuffer->isShared()) { 2090 Workers::singleton().broadcast( 2091 [&] (const AbstractLocker& locker, Worker& worker) { 2092 ArrayBuffer* nativeBuffer = jsBuffer->impl(); 2093 ArrayBufferContents contents; 2094 nativeBuffer->transferTo(vm, contents); // "transferTo" means "share" if the buffer is shared. 2095 RefPtr<Message> message = adoptRef(new Message(WTFMove(contents), index)); 2096 worker.enqueue(locker, message); 2097 }); 2098 return JSValue::encode(jsUndefined()); 2099 } 2100 2101 #if ENABLE(WEBASSEMBLY) 2102 JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, callFrame->argument(0)); 2103 if (memory && memory->memory().sharingMode() == Wasm::MemorySharingMode::Shared) { 2104 Workers::singleton().broadcast( 2105 [&] (const AbstractLocker& locker, Worker& worker) { 2106 Ref<Wasm::MemoryHandle> handle { memory->memory().handle() }; 2107 RefPtr<Message> message = adoptRef(new Message(WTFMove(handle), index)); 2108 worker.enqueue(locker, message); 2109 }); 2110 return JSValue::encode(jsUndefined()); 2111 } 2112 #endif 2113 2114 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Not supported object"_s))); 2115 } 2116 2117 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentGetReport, (JSGlobalObject* globalObject, CallFrame*)) 2118 { 2119 VM& vm = globalObject->vm(); 2120 2121 String string = Workers::singleton().tryGetReport(); 2122 if (!string) 2123 return JSValue::encode(jsNull()); 2124 2125 return JSValue::encode(jsString(vm, string)); 2126 } 2127 2128 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentLeaving, (JSGlobalObject*, CallFrame*)) 2129 { 2130 return JSValue::encode(jsUndefined()); 2131 } 2132 2133 JSC_DEFINE_HOST_FUNCTION(functionDollarAgentMonotonicNow, (JSGlobalObject*, CallFrame*)) 2134 { 2135 return JSValue::encode(jsNumber(MonotonicTime::now().secondsSinceEpoch().milliseconds())); 2136 } 2137 2138 JSC_DEFINE_HOST_FUNCTION(functionWaitForReport, (JSGlobalObject* globalObject, CallFrame*)) 2139 { 2140 VM& vm = globalObject->vm(); 2141 2142 String string; 2143 { 2144 ReleaseHeapAccessScope releaseAccess(vm.heap); 2145 string = Workers::singleton().getReport(); 2146 } 2147 if (!string) 2148 return JSValue::encode(jsNull()); 2149 2150 return JSValue::encode(jsString(vm, string)); 2151 } 2152 2153 JSC_DEFINE_HOST_FUNCTION(functionHeapCapacity, (JSGlobalObject* globalObject, CallFrame*)) 2154 { 2155 VM& vm = globalObject->vm(); 2156 return JSValue::encode(jsNumber(vm.heap.capacity())); 2157 } 2158 2159 JSC_DEFINE_HOST_FUNCTION(functionFlashHeapAccess, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2160 { 2161 VM& vm = globalObject->vm(); 2162 auto scope = DECLARE_THROW_SCOPE(vm); 2163 2164 double sleepTimeMs = 0; 2165 if (callFrame->argumentCount() >= 1) { 2166 sleepTimeMs = callFrame->argument(0).toNumber(globalObject); 2167 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2168 } 2169 2170 vm.heap.releaseAccess(); 2171 if (sleepTimeMs) 2172 sleep(Seconds::fromMilliseconds(sleepTimeMs)); 2173 vm.heap.acquireAccess(); 2174 return JSValue::encode(jsUndefined()); 2175 } 2176 2177 JSC_DEFINE_HOST_FUNCTION(functionDisableRichSourceInfo, (JSGlobalObject*, CallFrame*)) 2178 { 2179 supportsRichSourceInfo = false; 2180 return JSValue::encode(jsUndefined()); 2181 } 2182 2183 JSC_DEFINE_HOST_FUNCTION(functionMallocInALoop, (JSGlobalObject*, CallFrame*)) 2184 { 2185 Vector<void*> ptrs; 2186 for (unsigned i = 0; i < 5000; ++i) 2187 ptrs.append(fastMalloc(1024 * 2)); 2188 for (void* ptr : ptrs) 2189 fastFree(ptr); 2190 return JSValue::encode(jsUndefined()); 2191 } 2192 2193 JSC_DEFINE_HOST_FUNCTION(functionTotalCompileTime, (JSGlobalObject*, CallFrame*)) 2194 { 2195 #if ENABLE(JIT) 2196 return JSValue::encode(jsNumber(JIT::totalCompileTime().milliseconds())); 2197 #else 2198 return JSValue::encode(jsNumber(0)); 2199 #endif 2200 } 2201 2202 template<typename ValueType> 2203 typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, const Identifier&, ValueType) { } 2204 2205 template<typename ValueType> 2206 typename std::enable_if<std::is_fundamental<ValueType>::value>::type addOption(VM& vm, JSObject* optionsObject, const Identifier& identifier, ValueType value) 2207 { 2208 optionsObject->putDirect(vm, identifier, JSValue(value)); 2209 } 2210 2211 JSC_DEFINE_HOST_FUNCTION(functionJSCOptions, (JSGlobalObject* globalObject, CallFrame*)) 2212 { 2213 VM& vm = globalObject->vm(); 2214 JSObject* optionsObject = constructEmptyObject(globalObject); 2215 #define READ_OPTION(type_, name_, defaultValue_, availability_, description_) \ 2216 addOption(vm, optionsObject, Identifier::fromString(vm, #name_), Options::name_()); 2217 FOR_EACH_JSC_OPTION(READ_OPTION) 2218 #undef READ_OPTION 2219 return JSValue::encode(optionsObject); 2220 } 2221 2222 JSC_DEFINE_HOST_FUNCTION(functionReoptimizationRetryCount, (JSGlobalObject*, CallFrame* callFrame)) 2223 { 2224 if (callFrame->argumentCount() < 1) 2225 return JSValue::encode(jsUndefined()); 2226 2227 CodeBlock* block = getSomeBaselineCodeBlockForFunction(callFrame->argument(0)); 2228 if (!block) 2229 return JSValue::encode(jsNumber(0)); 2230 2231 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter())); 2232 } 2233 2234 JSC_DEFINE_HOST_FUNCTION(functionTransferArrayBuffer, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2235 { 2236 VM& vm = globalObject->vm(); 2237 auto scope = DECLARE_THROW_SCOPE(vm); 2238 2239 if (callFrame->argumentCount() < 1) 2240 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Not enough arguments"_s))); 2241 2242 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(vm, callFrame->argument(0)); 2243 if (!buffer) 2244 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Expected an array buffer"_s))); 2245 2246 ArrayBufferContents dummyContents; 2247 buffer->impl()->transferTo(vm, dummyContents); 2248 2249 return JSValue::encode(jsUndefined()); 2250 } 2251 2252 JSC_DEFINE_HOST_FUNCTION(functionFailNextNewCodeBlock, (JSGlobalObject* globalObject, CallFrame*)) 2253 { 2254 VM& vm = globalObject->vm(); 2255 vm.setFailNextNewCodeBlock(); 2256 return JSValue::encode(jsUndefined()); 2257 } 2258 2259 JSC_DEFINE_HOST_FUNCTION(functionQuit, (JSGlobalObject* globalObject, CallFrame*)) 2260 { 2261 VM& vm = globalObject->vm(); 2262 vm.codeCache()->write(vm); 2263 2264 jscExit(EXIT_SUCCESS); 2265 2266 #if COMPILER(MSVC) 2267 // Without this, Visual Studio will complain that this method does not return a value. 2268 return JSValue::encode(jsUndefined()); 2269 #endif 2270 } 2271 2272 JSC_DEFINE_HOST_FUNCTION(functionFalse, (JSGlobalObject*, CallFrame*)) 2273 { 2274 return JSValue::encode(jsBoolean(false)); 2275 } 2276 2277 JSC_DEFINE_HOST_FUNCTION(functionUndefined1, (JSGlobalObject*, CallFrame*)) 2278 { 2279 return JSValue::encode(jsUndefined()); 2280 } 2281 2282 JSC_DEFINE_HOST_FUNCTION(functionUndefined2, (JSGlobalObject*, CallFrame*)) 2283 { 2284 return JSValue::encode(jsUndefined()); 2285 } 2286 2287 JSC_DEFINE_HOST_FUNCTION(functionIsInt32, (JSGlobalObject*, CallFrame* callFrame)) 2288 { 2289 for (size_t i = 0; i < callFrame->argumentCount(); ++i) { 2290 if (!callFrame->argument(i).isInt32()) 2291 return JSValue::encode(jsBoolean(false)); 2292 } 2293 return JSValue::encode(jsBoolean(true)); 2294 } 2295 2296 JSC_DEFINE_HOST_FUNCTION(functionIsPureNaN, (JSGlobalObject*, CallFrame* callFrame)) 2297 { 2298 for (size_t i = 0; i < callFrame->argumentCount(); ++i) { 2299 JSValue value = callFrame->argument(i); 2300 if (!value.isNumber()) 2301 return JSValue::encode(jsBoolean(false)); 2302 double number = value.asNumber(); 2303 if (!std::isnan(number)) 2304 return JSValue::encode(jsBoolean(false)); 2305 if (isImpureNaN(number)) 2306 return JSValue::encode(jsBoolean(false)); 2307 } 2308 return JSValue::encode(jsBoolean(true)); 2309 } 2310 2311 JSC_DEFINE_HOST_FUNCTION(functionIdentity, (JSGlobalObject*, CallFrame* callFrame)) 2312 { 2313 return JSValue::encode(callFrame->argument(0)); 2314 } 2315 2316 JSC_DEFINE_HOST_FUNCTION(functionEffectful42, (JSGlobalObject*, CallFrame*)) 2317 { 2318 return JSValue::encode(jsNumber(42)); 2319 } 2320 2321 JSC_DEFINE_HOST_FUNCTION(functionMakeMasquerader, (JSGlobalObject* globalObject, CallFrame*)) 2322 { 2323 VM& vm = globalObject->vm(); 2324 return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, "IsHTMLDDA"_s, functionCallMasquerader)); 2325 } 2326 2327 JSC_DEFINE_HOST_FUNCTION(functionCallMasquerader, (JSGlobalObject*, CallFrame*)) 2328 { 2329 return JSValue::encode(jsNull()); 2330 } 2331 2332 JSC_DEFINE_HOST_FUNCTION(functionHasCustomProperties, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2333 { 2334 JSValue value = callFrame->argument(0); 2335 if (value.isObject()) 2336 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties(globalObject->vm()))); 2337 return JSValue::encode(jsBoolean(false)); 2338 } 2339 2340 JSC_DEFINE_HOST_FUNCTION(functionDumpTypesForAllVariables, (JSGlobalObject* globalObject, CallFrame*)) 2341 { 2342 VM& vm = globalObject->vm(); 2343 vm.dumpTypeProfilerData(); 2344 return JSValue::encode(jsUndefined()); 2345 } 2346 2347 JSC_DEFINE_HOST_FUNCTION(functionDrainMicrotasks, (JSGlobalObject* globalObject, CallFrame*)) 2348 { 2349 VM& vm = globalObject->vm(); 2350 vm.drainMicrotasks(); 2351 return JSValue::encode(jsUndefined()); 2352 } 2353 2354 JSC_DEFINE_HOST_FUNCTION(functionSetTimeout, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2355 { 2356 VM& vm = globalObject->vm(); 2357 auto scope = DECLARE_THROW_SCOPE(vm); 2358 2359 // FIXME: This means we can't pass any internal function but I don't think that's common for testing. 2360 auto callback = jsDynamicCast<JSFunction*>(vm, callFrame->argument(0)); 2361 if (!callback) 2362 return throwVMTypeError(globalObject, scope, "First argument is not a JS function"_s); 2363 2364 // FIXME: We don't look at the timeout parameter because we don't have a schedule work later API. 2365 vm.deferredWorkTimer->addPendingWork(vm, callback, { }); 2366 vm.deferredWorkTimer->scheduleWorkSoon(callback, [callback] { 2367 JSGlobalObject* globalObject = callback->globalObject(); 2368 VM& vm = globalObject->vm(); 2369 2370 MarkedArgumentBuffer args; 2371 call(globalObject, callback, jsUndefined(), args, "You shouldn't see this..."); 2372 vm.deferredWorkTimer->cancelPendingWork(callback); 2373 }); 2374 return JSValue::encode(jsUndefined()); 2375 } 2376 2377 JSC_DEFINE_HOST_FUNCTION(functionReleaseWeakRefs, (JSGlobalObject* globalObject, CallFrame*)) 2378 { 2379 VM& vm = globalObject->vm(); 2380 vm.finalizeSynchronousJSExecution(); 2381 return JSValue::encode(jsUndefined()); 2382 } 2383 2384 JSC_DEFINE_HOST_FUNCTION(functionFinalizationRegistryLiveCount, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2385 { 2386 VM& vm = globalObject->vm(); 2387 auto scope = DECLARE_THROW_SCOPE(vm); 2388 2389 auto* finalizationRegistry = jsDynamicCast<JSFinalizationRegistry*>(vm, callFrame->argument(0)); 2390 if (!finalizationRegistry) 2391 return throwVMTypeError(globalObject, scope, "first argument is not a finalizationRegistry"_s); 2392 2393 auto locker = holdLock(finalizationRegistry->cellLock()); 2394 return JSValue::encode(jsNumber(finalizationRegistry->liveCount(locker))); 2395 } 2396 2397 JSC_DEFINE_HOST_FUNCTION(functionFinalizationRegistryDeadCount, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2398 { 2399 VM& vm = globalObject->vm(); 2400 auto scope = DECLARE_THROW_SCOPE(vm); 2401 2402 auto* finalizationRegistry = jsDynamicCast<JSFinalizationRegistry*>(vm, callFrame->argument(0)); 2403 if (!finalizationRegistry) 2404 return throwVMTypeError(globalObject, scope, "first argument is not a finalizationRegistry"_s); 2405 2406 auto locker = holdLock(finalizationRegistry->cellLock()); 2407 return JSValue::encode(jsNumber(finalizationRegistry->deadCount(locker))); 2408 } 2409 2410 JSC_DEFINE_HOST_FUNCTION(functionIs32BitPlatform, (JSGlobalObject*, CallFrame*)) 2411 { 2412 #if USE(JSVALUE64) 2413 return JSValue::encode(JSValue(JSC::JSValue::JSFalse)); 2414 #else 2415 return JSValue::encode(JSValue(JSC::JSValue::JSTrue)); 2416 #endif 2417 } 2418 2419 JSC_DEFINE_HOST_FUNCTION(functionCreateGlobalObject, (JSGlobalObject* globalObject, CallFrame*)) 2420 { 2421 VM& vm = globalObject->vm(); 2422 return JSValue::encode(GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>())); 2423 } 2424 2425 JSC_DEFINE_HOST_FUNCTION(functionCreateHeapBigInt, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2426 { 2427 VM& vm = globalObject->vm(); 2428 auto scope = DECLARE_THROW_SCOPE(vm); 2429 JSValue argument = callFrame->argument(0); 2430 JSValue bigInt = argument.toBigInt(globalObject); 2431 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2432 #if USE(BIGINT32) 2433 if (bigInt.isHeapBigInt()) 2434 return JSValue::encode(bigInt); 2435 ASSERT(bigInt.isBigInt32()); 2436 int32_t value = bigInt.bigInt32AsInt32(); 2437 RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::createFrom(globalObject, value))); 2438 #else 2439 return JSValue::encode(bigInt); 2440 #endif 2441 } 2442 2443 #if USE(BIGINT32) 2444 JSC_DEFINE_HOST_FUNCTION(functionCreateBigInt32, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2445 { 2446 VM& vm = globalObject->vm(); 2447 auto scope = DECLARE_THROW_SCOPE(vm); 2448 JSValue argument = callFrame->argument(0); 2449 JSValue bigIntValue = argument.toBigInt(globalObject); 2450 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2451 if (bigIntValue.isBigInt32()) 2452 return JSValue::encode(bigIntValue); 2453 ASSERT(bigIntValue.isHeapBigInt()); 2454 JSBigInt* bigInt = jsCast<JSBigInt*>(bigIntValue); 2455 if (!bigInt->length()) 2456 return JSValue::encode(jsBigInt32(0)); 2457 if (bigInt->length() == 1) { 2458 JSBigInt::Digit digit = bigInt->digit(0); 2459 if (bigInt->sign()) { 2460 if (digit <= static_cast<uint64_t>(-static_cast<int64_t>(INT32_MIN))) 2461 return JSValue::encode(jsBigInt32(static_cast<int32_t>(-static_cast<int64_t>(digit)))); 2462 } else { 2463 if (digit <= INT32_MAX) 2464 return JSValue::encode(jsBigInt32(static_cast<int32_t>(digit))); 2465 } 2466 } 2467 throwTypeError(globalObject, scope, "Out of range of BigInt32"_s); 2468 return { }; 2469 } 2470 #endif 2471 2472 JSC_DEFINE_HOST_FUNCTION(functionUseBigInt32, (JSGlobalObject*, CallFrame*)) 2473 { 2474 #if USE(BIGINT32) 2475 return JSValue::encode(jsBoolean(true)); 2476 #else 2477 return JSValue::encode(jsBoolean(false)); 2478 #endif 2479 } 2480 2481 JSC_DEFINE_HOST_FUNCTION(functionIsBigInt32, (JSGlobalObject*, CallFrame* callFrame)) 2482 { 2483 #if USE(BIGINT32) 2484 return JSValue::encode(jsBoolean(callFrame->argument(0).isBigInt32())); 2485 #else 2486 UNUSED_PARAM(callFrame); 2487 return JSValue::encode(jsBoolean(false)); 2488 #endif 2489 } 2490 2491 JSC_DEFINE_HOST_FUNCTION(functionIsHeapBigInt, (JSGlobalObject*, CallFrame* callFrame)) 2492 { 2493 return JSValue::encode(jsBoolean(callFrame->argument(0).isHeapBigInt())); 2494 } 2495 2496 JSC_DEFINE_HOST_FUNCTION(functionCheckModuleSyntax, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2497 { 2498 VM& vm = globalObject->vm(); 2499 auto scope = DECLARE_THROW_SCOPE(vm); 2500 2501 String source = callFrame->argument(0).toWTFString(globalObject); 2502 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2503 2504 StopWatch stopWatch; 2505 stopWatch.start(); 2506 2507 ParserError error; 2508 bool validSyntax = checkModuleSyntax(globalObject, jscSource(source, { }, String(), TextPosition(), SourceProviderSourceType::Module), error); 2509 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2510 stopWatch.stop(); 2511 2512 if (!validSyntax) 2513 throwException(globalObject, scope, jsNontrivialString(vm, toString("SyntaxError: ", error.message(), ":", error.line()))); 2514 return JSValue::encode(jsNumber(stopWatch.getElapsedMS())); 2515 } 2516 2517 JSC_DEFINE_HOST_FUNCTION(functionPlatformSupportsSamplingProfiler, (JSGlobalObject*, CallFrame*)) 2518 { 2519 #if ENABLE(SAMPLING_PROFILER) 2520 return JSValue::encode(JSValue(JSC::JSValue::JSTrue)); 2521 #else 2522 return JSValue::encode(JSValue(JSC::JSValue::JSFalse)); 2523 #endif 2524 } 2525 2526 JSC_DEFINE_HOST_FUNCTION(functionGenerateHeapSnapshot, (JSGlobalObject* globalObject, CallFrame*)) 2527 { 2528 VM& vm = globalObject->vm(); 2529 JSLockHolder lock(vm); 2530 auto scope = DECLARE_THROW_SCOPE(vm); 2531 2532 HeapSnapshotBuilder snapshotBuilder(vm.ensureHeapProfiler()); 2533 snapshotBuilder.buildSnapshot(); 2534 2535 String jsonString = snapshotBuilder.json(); 2536 EncodedJSValue result = JSValue::encode(JSONParse(globalObject, jsonString)); 2537 scope.releaseAssertNoException(); 2538 return result; 2539 } 2540 2541 JSC_DEFINE_HOST_FUNCTION(functionGenerateHeapSnapshotForGCDebugging, (JSGlobalObject* globalObject, CallFrame*)) 2542 { 2543 VM& vm = globalObject->vm(); 2544 JSLockHolder lock(vm); 2545 auto scope = DECLARE_THROW_SCOPE(vm); 2546 String jsonString; 2547 { 2548 DeferGCForAWhile deferGC(vm.heap); // Prevent concurrent GC from interfering with the full GC that the snapshot does. 2549 2550 HeapSnapshotBuilder snapshotBuilder(vm.ensureHeapProfiler(), HeapSnapshotBuilder::SnapshotType::GCDebuggingSnapshot); 2551 snapshotBuilder.buildSnapshot(); 2552 2553 jsonString = snapshotBuilder.json(); 2554 } 2555 scope.releaseAssertNoException(); 2556 return JSValue::encode(jsString(vm, jsonString)); 2557 } 2558 2559 JSC_DEFINE_HOST_FUNCTION(functionResetSuperSamplerState, (JSGlobalObject*, CallFrame*)) 2560 { 2561 resetSuperSamplerState(); 2562 return JSValue::encode(jsUndefined()); 2563 } 2564 2565 JSC_DEFINE_HOST_FUNCTION(functionEnsureArrayStorage, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2566 { 2567 VM& vm = globalObject->vm(); 2568 for (unsigned i = 0; i < callFrame->argumentCount(); ++i) { 2569 if (JSObject* object = jsDynamicCast<JSObject*>(vm, callFrame->argument(i))) 2570 object->ensureArrayStorage(vm); 2571 } 2572 return JSValue::encode(jsUndefined()); 2573 } 2574 2575 #if ENABLE(SAMPLING_PROFILER) 2576 JSC_DEFINE_HOST_FUNCTION(functionStartSamplingProfiler, (JSGlobalObject* globalObject, CallFrame*)) 2577 { 2578 VM& vm = globalObject->vm(); 2579 SamplingProfiler& samplingProfiler = vm.ensureSamplingProfiler(WTF::Stopwatch::create()); 2580 samplingProfiler.noticeCurrentThreadAsJSCExecutionThread(); 2581 samplingProfiler.start(); 2582 return JSValue::encode(jsUndefined()); 2583 } 2584 2585 JSC_DEFINE_HOST_FUNCTION(functionSamplingProfilerStackTraces, (JSGlobalObject* globalObject, CallFrame*)) 2586 { 2587 VM& vm = globalObject->vm(); 2588 auto scope = DECLARE_THROW_SCOPE(vm); 2589 2590 if (!vm.samplingProfiler()) 2591 return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Sampling profiler was never started"_s))); 2592 2593 String jsonString = vm.samplingProfiler()->stackTracesAsJSON(); 2594 EncodedJSValue result = JSValue::encode(JSONParse(globalObject, jsonString)); 2595 scope.releaseAssertNoException(); 2596 return result; 2597 } 2598 #endif // ENABLE(SAMPLING_PROFILER) 2599 2600 JSC_DEFINE_HOST_FUNCTION(functionMaxArguments, (JSGlobalObject*, CallFrame*)) 2601 { 2602 return JSValue::encode(jsNumber(JSC::maxArguments)); 2603 } 2604 2605 JSC_DEFINE_HOST_FUNCTION(functionAsyncTestStart, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2606 { 2607 VM& vm = globalObject->vm(); 2608 auto scope = DECLARE_THROW_SCOPE(vm); 2609 2610 JSValue numberOfAsyncPasses = callFrame->argument(0); 2611 if (!numberOfAsyncPasses.isUInt32()) 2612 return throwVMError(globalObject, scope, "Expected first argument to be a uint32"_s); 2613 2614 asyncTestExpectedPasses += numberOfAsyncPasses.asUInt32(); 2615 return encodedJSUndefined(); 2616 } 2617 2618 JSC_DEFINE_HOST_FUNCTION(functionAsyncTestPassed, (JSGlobalObject*, CallFrame*)) 2619 { 2620 asyncTestPasses++; 2621 return encodedJSUndefined(); 2622 } 2623 2624 #if ENABLE(WEBASSEMBLY) 2625 2626 JSC_DEFINE_HOST_FUNCTION(functionWebAssemblyMemoryMode, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2627 { 2628 VM& vm = globalObject->vm(); 2629 auto scope = DECLARE_THROW_SCOPE(vm); 2630 2631 if (!Wasm::isSupported()) 2632 return throwVMTypeError(globalObject, scope, "WebAssemblyMemoryMode should only be called if the useWebAssembly option is set"_s); 2633 2634 if (JSObject* object = callFrame->argument(0).getObject()) { 2635 if (auto* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, object)) 2636 return JSValue::encode(jsString(vm, makeString(memory->memory().mode()))); 2637 if (auto* instance = jsDynamicCast<JSWebAssemblyInstance*>(vm, object)) 2638 return JSValue::encode(jsString(vm, makeString(instance->memoryMode()))); 2639 } 2640 2641 return throwVMTypeError(globalObject, scope, "WebAssemblyMemoryMode expects either a WebAssembly.Memory or WebAssembly.Instance"_s); 2642 } 2643 2644 #endif // ENABLE(WEBASSEMBLY) 2645 2646 JSC_DEFINE_HOST_FUNCTION(functionSetUnhandledRejectionCallback, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2647 { 2648 VM& vm = globalObject->vm(); 2649 JSObject* object = callFrame->argument(0).getObject(); 2650 auto scope = DECLARE_THROW_SCOPE(vm); 2651 2652 if (!object || !object->isCallable(vm)) 2653 return throwVMTypeError(globalObject, scope); 2654 2655 globalObject->setUnhandledRejectionCallback(vm, object); 2656 return JSValue::encode(jsUndefined()); 2657 } 2658 2659 JSC_DEFINE_HOST_FUNCTION(functionAsDoubleNumber, (JSGlobalObject* globalObject, CallFrame* callFrame)) 2660 { 2661 VM& vm = globalObject->vm(); 2662 auto scope = DECLARE_THROW_SCOPE(vm); 2663 double num = callFrame->argument(0).toNumber(globalObject); 2664 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2665 return JSValue::encode(jsDoubleNumber(num)); 2666 } 2667 2668 JSC_DEFINE_HOST_FUNCTION(functionDropAllLocks, (JSGlobalObject* globalObject, CallFrame*)) 2669 { 2670 JSLock::DropAllLocks dropAllLocks(globalObject); 2671 return JSValue::encode(jsUndefined()); 2672 } 2673 2674 // Use SEH for Release builds only to get rid of the crash report dialog 2675 // (luckily the same tests fail in Release and Debug builds so far). Need to 2676 // be in a separate main function because the jscmain function requires object 2677 // unwinding. 2678 2679 #if COMPILER(MSVC) && !defined(_DEBUG) 2680 #define TRY __try { 2681 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; } 2682 #else 2683 #define TRY 2684 #define EXCEPT(x) 2685 #endif 2686 2687 int jscmain(int argc, char** argv); 2688 2689 #if OS(DARWIN) || OS(LINUX) 2690 static size_t memoryLimit; 2691 2692 static void crashIfExceedingMemoryLimit() 2693 { 2694 if (!memoryLimit) 2695 return; 2696 MemoryFootprint footprint = MemoryFootprint::now(); 2697 if (footprint.current > memoryLimit) { 2698 dataLogLn("Crashing because current footprint: ", footprint.current, " exceeds limit: ", memoryLimit); 2699 CRASH(); 2700 } 2701 } 2702 2703 static void startMemoryMonitoringThreadIfNeeded() 2704 { 2705 char* memoryLimitString = getenv("JSCTEST_memoryLimit"); 2706 if (!memoryLimitString) 2707 return; 2708 2709 if (sscanf(memoryLimitString, "%zu", &memoryLimit) != 1) { 2710 dataLogLn("WARNING: malformed JSCTEST_memoryLimit environment variable"); 2711 return; 2712 } 2713 2714 if (!memoryLimit) 2715 return; 2716 2717 Thread::create("jsc Memory Monitor", [=] { 2718 while (true) { 2719 sleep(Seconds::fromMilliseconds(5)); 2720 crashIfExceedingMemoryLimit(); 2721 } 2722 }); 2723 } 2724 #endif // OS(DARWIN) || OS(LINUX) 2725 2726 static double s_desiredTimeout; 2727 static double s_timeoutMultiplier = 1.0; 2728 static Seconds s_timeoutDuration; 2729 static Seconds s_maxAllowedCPUTime; 2730 static VM* s_vm; 2731 2732 static void startTimeoutTimer(Seconds duration) 2733 { 2734 Thread::create("jsc Timeout Thread", [=] () { 2735 sleep(duration); 2736 VMInspector::forEachVM([&] (VM& vm) -> VMInspector::FunctorStatus { 2737 if (&vm != s_vm) 2738 return VMInspector::FunctorStatus::Continue; 2739 vm.notifyNeedShellTimeoutCheck(); 2740 return VMInspector::FunctorStatus::Done; 2741 }); 2742 2743 if (const char* timeoutString = getenv("JSCTEST_hardTimeout")) { 2744 double hardTimeoutInDouble = 0; 2745 if (sscanf(timeoutString, "%lf", &hardTimeoutInDouble) != 1) 2746 dataLog("WARNING: hardTimeout string is malformed, got ", timeoutString, " but expected a number. Not using a timeout.\n"); 2747 else { 2748 Seconds hardTimeout { hardTimeoutInDouble }; 2749 sleep(hardTimeout); 2750 dataLogLn("HARD TIMEOUT after ", hardTimeout); 2751 exit(EXIT_FAILURE); 2752 } 2753 } 2754 }); 2755 } 2756 2757 static void timeoutCheckCallback(VM& vm) 2758 { 2759 RELEASE_ASSERT(&vm == s_vm); 2760 auto cpuTime = CPUTime::forCurrentThread(); 2761 if (cpuTime >= s_maxAllowedCPUTime) { 2762 dataLog("Timed out after ", s_timeoutDuration, " seconds!\n"); 2763 CRASH(); 2764 } 2765 auto remainingTime = s_maxAllowedCPUTime - cpuTime; 2766 startTimeoutTimer(remainingTime); 2767 } 2768 2769 static void initializeTimeoutIfNeeded() 2770 { 2771 if (char* timeoutString = getenv("JSCTEST_timeout")) { 2772 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) { 2773 dataLog("WARNING: timeout string is malformed, got ", timeoutString, 2774 " but expected a number. Not using a timeout.\n"); 2775 } else 2776 g_jscConfig.shellTimeoutCheckCallback = timeoutCheckCallback; 2777 } 2778 } 2779 2780 static void startTimeoutThreadIfNeeded(VM& vm) 2781 { 2782 if (!g_jscConfig.shellTimeoutCheckCallback) 2783 return; 2784 2785 s_vm = &vm; 2786 s_timeoutDuration = Seconds(s_desiredTimeout * s_timeoutMultiplier); 2787 s_maxAllowedCPUTime = CPUTime::forCurrentThread() + s_timeoutDuration; 2788 Seconds timeoutDuration(s_desiredTimeout * s_timeoutMultiplier); 2789 startTimeoutTimer(timeoutDuration); 2790 } 2791 2792 int main(int argc, char** argv) 2793 { 2794 #if OS(DARWIN) && CPU(ARM_THUMB2) 2795 // Enabled IEEE754 denormal support. 2796 fenv_t env; 2797 fegetenv( &env ); 2798 env.__fpscr &= ~0x01000000u; 2799 fesetenv( &env ); 2800 #endif 2801 2802 #if OS(WINDOWS) 2803 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for 2804 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the 2805 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. 2806 ::SetErrorMode(0); 2807 2808 _setmode(_fileno(stdout), _O_BINARY); 2809 _setmode(_fileno(stderr), _O_BINARY); 2810 2811 #if defined(_DEBUG) 2812 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); 2813 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); 2814 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 2815 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); 2816 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); 2817 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); 2818 #endif 2819 2820 timeBeginPeriod(1); 2821 #endif 2822 2823 #if PLATFORM(GTK) 2824 if (!setlocale(LC_ALL, "")) 2825 WTFLogAlways("Locale not supported by C library.\n\tUsing the fallback 'C' locale."); 2826 #endif 2827 2828 // Need to initialize WTF before we start any threads. Cannot initialize JSC 2829 // yet, since that would do somethings that we'd like to defer until after we 2830 // have a chance to parse options. 2831 WTF::initialize(); 2832 2833 // We can't use destructors in the following code because it uses Windows 2834 // Structured Exception Handling 2835 int res = EXIT_SUCCESS; 2836 TRY 2837 res = jscmain(argc, argv); 2838 EXCEPT(res = EXIT_EXCEPTION) 2839 finalizeStatsAtEndOfTesting(); 2840 if (getenv("JS_SHELL_WAIT_FOR_INPUT_TO_EXIT")) { 2841 WTF::fastDisableScavenger(); 2842 fprintf(stdout, "\njs shell waiting for input to exit\n"); 2843 fflush(stdout); 2844 getc(stdin); 2845 } 2846 2847 jscExit(res); 2848 } 2849 2850 static void dumpException(GlobalObject* globalObject, JSValue exception) 2851 { 2852 VM& vm = globalObject->vm(); 2853 auto scope = DECLARE_CATCH_SCOPE(vm); 2854 2855 #define CHECK_EXCEPTION() do { \ 2856 if (scope.exception()) { \ 2857 scope.clearException(); \ 2858 return; \ 2859 } \ 2860 } while (false) 2861 2862 auto exceptionString = exception.toWTFString(globalObject); 2863 CHECK_EXCEPTION(); 2864 Expected<CString, UTF8ConversionError> expectedCString = exceptionString.tryGetUtf8(); 2865 if (expectedCString) 2866 printf("Exception: %s\n", expectedCString.value().data()); 2867 else 2868 printf("Exception: <out of memory while extracting exception string>\n"); 2869 2870 Identifier nameID = Identifier::fromString(vm, "name"); 2871 CHECK_EXCEPTION(); 2872 Identifier fileNameID = Identifier::fromString(vm, "sourceURL"); 2873 CHECK_EXCEPTION(); 2874 Identifier lineNumberID = Identifier::fromString(vm, "line"); 2875 CHECK_EXCEPTION(); 2876 Identifier stackID = Identifier::fromString(vm, "stack"); 2877 CHECK_EXCEPTION(); 2878 2879 JSValue nameValue = exception.get(globalObject, nameID); 2880 CHECK_EXCEPTION(); 2881 JSValue fileNameValue = exception.get(globalObject, fileNameID); 2882 CHECK_EXCEPTION(); 2883 JSValue lineNumberValue = exception.get(globalObject, lineNumberID); 2884 CHECK_EXCEPTION(); 2885 JSValue stackValue = exception.get(globalObject, stackID); 2886 CHECK_EXCEPTION(); 2887 2888 auto nameString = nameValue.toWTFString(globalObject); 2889 CHECK_EXCEPTION(); 2890 2891 if (nameString == "SyntaxError" && (!fileNameValue.isUndefinedOrNull() || !lineNumberValue.isUndefinedOrNull())) { 2892 auto fileNameString = fileNameValue.toWTFString(globalObject); 2893 CHECK_EXCEPTION(); 2894 auto lineNumberString = lineNumberValue.toWTFString(globalObject); 2895 CHECK_EXCEPTION(); 2896 printf("at %s:%s\n", fileNameString.utf8().data(), lineNumberString.utf8().data()); 2897 } 2898 2899 if (!stackValue.isUndefinedOrNull()) { 2900 auto stackString = stackValue.toWTFString(globalObject); 2901 CHECK_EXCEPTION(); 2902 if (stackString.length()) 2903 printf("%s\n", stackString.utf8().data()); 2904 } 2905 2906 #undef CHECK_EXCEPTION 2907 } 2908 2909 static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue exception, const CommandLine& options) 2910 { 2911 const String& expectedExceptionName = options.m_uncaughtExceptionName; 2912 auto scope = DECLARE_CATCH_SCOPE(vm); 2913 scope.clearException(); 2914 if (!exception) { 2915 printf("Expected uncaught exception with name '%s' but none was thrown\n", expectedExceptionName.utf8().data()); 2916 return false; 2917 } 2918 2919 JSValue exceptionClass = globalObject->get(globalObject, Identifier::fromString(vm, expectedExceptionName)); 2920 if (!exceptionClass.isObject() || scope.exception()) { 2921 printf("Expected uncaught exception with name '%s' but given exception class is not defined\n", expectedExceptionName.utf8().data()); 2922 return false; 2923 } 2924 2925 bool isInstanceOfExpectedException = jsCast<JSObject*>(exceptionClass)->hasInstance(globalObject, exception); 2926 if (scope.exception()) { 2927 printf("Expected uncaught exception with name '%s' but given exception class fails performing hasInstance\n", expectedExceptionName.utf8().data()); 2928 return false; 2929 } 2930 if (isInstanceOfExpectedException) { 2931 if (options.m_alwaysDumpUncaughtException) 2932 dumpException(globalObject, exception); 2933 return true; 2934 } 2935 2936 printf("Expected uncaught exception with name '%s' but exception value is not instance of this exception class\n", expectedExceptionName.utf8().data()); 2937 dumpException(globalObject, exception); 2938 return false; 2939 } 2940 2941 static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, const CommandLine& options, bool& success) 2942 { 2943 VM& vm = globalObject->vm(); 2944 2945 if (options.m_treatWatchdogExceptionAsSuccess && value.inherits<TerminatedExecutionError>(vm)) { 2946 ASSERT(hasException); 2947 return; 2948 } 2949 2950 if (!options.m_uncaughtExceptionName || !isLastFile) { 2951 success = success && !hasException; 2952 if (options.m_dump && !hasException) 2953 printf("End: %s\n", value.toWTFString(globalObject).utf8().data()); 2954 if (hasException) 2955 dumpException(globalObject, value); 2956 } else 2957 success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), options); 2958 } 2959 2960 void GlobalObject::reportUncaughtExceptionAtEventLoop(JSGlobalObject* globalObject, Exception* exception) 2961 { 2962 auto* global = jsCast<GlobalObject*>(globalObject); 2963 dumpException(global, exception->value()); 2964 bool hideNoReturn = true; 2965 if (hideNoReturn) 2966 jscExit(EXIT_EXCEPTION); 2967 } 2968 2969 static void runWithOptions(GlobalObject* globalObject, CommandLine& options, bool& success) 2970 { 2971 Vector<Script>& scripts = options.m_scripts; 2972 String fileName; 2973 Vector<char> scriptBuffer; 2974 2975 VM& vm = globalObject->vm(); 2976 auto scope = DECLARE_CATCH_SCOPE(vm); 2977 2978 #if ENABLE(SAMPLING_FLAGS) 2979 SamplingFlags::start(); 2980 #endif 2981 2982 for (size_t i = 0; i < scripts.size(); i++) { 2983 JSInternalPromise* promise = nullptr; 2984 bool isModule = options.m_module || scripts[i].scriptType == Script::ScriptType::Module; 2985 if (scripts[i].codeSource == Script::CodeSource::File) { 2986 fileName = scripts[i].argument; 2987 if (scripts[i].strictMode == Script::StrictMode::Strict) 2988 scriptBuffer.append("\"use strict\";\n", strlen("\"use strict\";\n")); 2989 2990 if (isModule) { 2991 // If the passed file isn't an absolute path append "./" so the module loader doesn't think this is a bare-name specifier. 2992 fileName = fileName.startsWith('/') ? fileName : makeString("./", fileName); 2993 promise = loadAndEvaluateModule(globalObject, fileName, jsUndefined(), jsUndefined()); 2994 scope.releaseAssertNoException(); 2995 } else { 2996 if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer)) { 2997 success = false; // fail early so we can catch missing files 2998 return; 2999 } 3000 } 3001 } else { 3002 size_t commandLineLength = strlen(scripts[i].argument); 3003 scriptBuffer.resize(commandLineLength); 3004 std::copy(scripts[i].argument, scripts[i].argument + commandLineLength, scriptBuffer.begin()); 3005 fileName = "[Command Line]"_s; 3006 } 3007 3008 bool isLastFile = i == scripts.size() - 1; 3009 SourceOrigin sourceOrigin { absolutePath(fileName) }; 3010 if (isModule) { 3011 if (!promise) { 3012 // FIXME: This should use an absolute file URL https://bugs.webkit.org/show_bug.cgi?id=193077 3013 promise = loadAndEvaluateModule(globalObject, jscSource(stringFromUTF(scriptBuffer), sourceOrigin, fileName, TextPosition(), SourceProviderSourceType::Module), jsUndefined()); 3014 RETURN_IF_EXCEPTION(scope, void()); 3015 } 3016 3017 JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&success, &options, isLastFile](JSGlobalObject* globalObject, CallFrame* callFrame) { 3018 checkException(jsCast<GlobalObject*>(globalObject), isLastFile, false, callFrame->argument(0), options, success); 3019 return JSValue::encode(jsUndefined()); 3020 }); 3021 3022 JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&success, &options, isLastFile](JSGlobalObject* globalObject, CallFrame* callFrame) { 3023 checkException(jsCast<GlobalObject*>(globalObject), isLastFile, true, callFrame->argument(0), options, success); 3024 return JSValue::encode(jsUndefined()); 3025 }); 3026 3027 promise->then(globalObject, fulfillHandler, rejectHandler); 3028 scope.releaseAssertNoException(); 3029 vm.drainMicrotasks(); 3030 } else { 3031 NakedPtr<Exception> evaluationException; 3032 JSValue returnValue = evaluate(globalObject, jscSource(scriptBuffer, sourceOrigin , fileName), JSValue(), evaluationException); 3033 scope.assertNoException(); 3034 if (evaluationException) 3035 returnValue = evaluationException->value(); 3036 checkException(globalObject, isLastFile, evaluationException, returnValue, options, success); 3037 } 3038 3039 scriptBuffer.clear(); 3040 scope.clearException(); 3041 } 3042 3043 #if ENABLE(REGEXP_TRACING) 3044 vm.dumpRegExpTrace(); 3045 #endif 3046 } 3047 3048 #define RUNNING_FROM_XCODE 0 3049 3050 static void runInteractive(GlobalObject* globalObject) 3051 { 3052 VM& vm = globalObject->vm(); 3053 auto scope = DECLARE_CATCH_SCOPE(vm); 3054 3055 URL directoryName = currentWorkingDirectory(); 3056 if (!directoryName.isValid()) 3057 return; 3058 SourceOrigin sourceOrigin(URL(directoryName, "./interpreter"_s)); 3059 3060 bool shouldQuit = false; 3061 while (!shouldQuit) { 3062 #if HAVE(READLINE) && !RUNNING_FROM_XCODE 3063 ParserError error; 3064 String source; 3065 do { 3066 error = ParserError(); 3067 char* line = readline(source.isEmpty() ? interactivePrompt : "... "); 3068 shouldQuit = !line; 3069 if (!line) 3070 break; 3071 source = source + String::fromUTF8(line); 3072 source = source + '\n'; 3073 checkSyntax(vm, jscSource(source, sourceOrigin), error); 3074 if (!line[0]) { 3075 free(line); 3076 break; 3077 } 3078 add_history(line); 3079 free(line); 3080 } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable); 3081 3082 if (error.isValid()) { 3083 printf("%s:%d\n", error.message().utf8().data(), error.line()); 3084 continue; 3085 } 3086 3087 3088 NakedPtr<Exception> evaluationException; 3089 JSValue returnValue = evaluate(globalObject, jscSource(source, sourceOrigin), JSValue(), evaluationException); 3090 #else 3091 printf("%s", interactivePrompt); 3092 Vector<char, 256> line; 3093 int c; 3094 while ((c = getchar()) != EOF) { 3095 // FIXME: Should we also break on \r? 3096 if (c == '\n') 3097 break; 3098 line.append(c); 3099 } 3100 if (line.isEmpty()) 3101 break; 3102 3103 NakedPtr<Exception> evaluationException; 3104 JSValue returnValue = evaluate(globalObject, jscSource(line, sourceOrigin, sourceOrigin.string()), JSValue(), evaluationException); 3105 #endif 3106 Expected<CString, UTF8ConversionError> utf8; 3107 if (evaluationException) { 3108 fputs("Exception: ", stdout); 3109 utf8 = evaluationException->value().toWTFString(globalObject).tryGetUtf8(); 3110 } else 3111 utf8 = returnValue.toWTFString(globalObject).tryGetUtf8(); 3112 3113 CString result; 3114 if (utf8) 3115 result = utf8.value(); 3116 else if (utf8.error() == UTF8ConversionError::OutOfMemory) 3117 result = "OutOfMemory while processing string"; 3118 else 3119 result = "Error while processing string"; 3120 fwrite(result.data(), sizeof(char), result.length(), stdout); 3121 putchar('\n'); 3122 3123 scope.clearException(); 3124 vm.drainMicrotasks(); 3125 } 3126 printf("\n"); 3127 } 3128 3129 static NO_RETURN void printUsageStatement(bool help = false) 3130 { 3131 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n"); 3132 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n"); 3133 fprintf(stderr, " -e Evaluate argument as script code\n"); 3134 fprintf(stderr, " -f Specifies a source file (deprecated)\n"); 3135 fprintf(stderr, " -h|--help Prints this help message\n"); 3136 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n"); 3137 fprintf(stderr, " -m Execute as a module\n"); 3138 #if OS(UNIX) 3139 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only, lldb will not work with this option) \n"); 3140 #endif 3141 fprintf(stderr, " -p <file> Outputs profiling data to a file\n"); 3142 fprintf(stderr, " -x Output exit code before terminating\n"); 3143 fprintf(stderr, "\n"); 3144 fprintf(stderr, " --sample Collects and outputs sampling profiler data\n"); 3145 fprintf(stderr, " --test262-async Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n"); 3146 fprintf(stderr, " --strict-file=<file> Parse the given file as if it were in strict mode (this option may be passed more than once)\n"); 3147 fprintf(stderr, " --module-file=<file> Parse and evaluate the given file as module (this option may be passed more than once)\n"); 3148 fprintf(stderr, " --exception=<name> Check the last script exits with an uncaught exception with the specified name\n"); 3149 fprintf(stderr, " --watchdog-exception-ok Uncaught watchdog exceptions exit with success\n"); 3150 fprintf(stderr, " --dumpException Dump uncaught exception text\n"); 3151 fprintf(stderr, " --footprint Dump memory footprint after done executing\n"); 3152 fprintf(stderr, " --options Dumps all JSC VM options and exits\n"); 3153 fprintf(stderr, " --dumpOptions Dumps all non-default JSC VM options before continuing\n"); 3154 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n"); 3155 fprintf(stderr, " --destroy-vm Destroy VM before exiting\n"); 3156 fprintf(stderr, " --can-block-is-false Make main thread's Atomics.wait throw\n"); 3157 fprintf(stderr, "\n"); 3158 fprintf(stderr, "Files with a .mjs extension will always be evaluated as modules.\n"); 3159 fprintf(stderr, "\n"); 3160 3161 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE); 3162 } 3163 3164 static bool isMJSFile(char *filename) 3165 { 3166 filename = strrchr(filename, '.'); 3167 3168 if (filename) 3169 return !strcmp(filename, ".mjs"); 3170 3171 return false; 3172 } 3173 3174 void CommandLine::parseArguments(int argc, char** argv) 3175 { 3176 Options::AllowUnfinalizedAccessScope scope; 3177 Options::initialize(); 3178 Options::useSharedArrayBuffer() = true; 3179 Options::useAtMethod() = true; 3180 3181 #if PLATFORM(IOS_FAMILY) 3182 Options::crashIfCantAllocateJITMemory() = true; 3183 #endif 3184 3185 if (Options::dumpOptions()) { 3186 printf("Command line:"); 3187 #if PLATFORM(COCOA) 3188 for (char** envp = *_NSGetEnviron(); *envp; envp++) { 3189 const char* env = *envp; 3190 if (!strncmp("JSC_", env, 4)) 3191 printf(" %s", env); 3192 } 3193 #endif // PLATFORM(COCOA) 3194 for (int i = 0; i < argc; ++i) 3195 printf(" %s", argv[i]); 3196 printf("\n"); 3197 } 3198 3199 int i = 1; 3200 JSC::Options::DumpLevel dumpOptionsLevel = JSC::Options::DumpLevel::None; 3201 bool needToExit = false; 3202 3203 bool hasBadJSCOptions = false; 3204 for (; i < argc; ++i) { 3205 const char* arg = argv[i]; 3206 if (!strcmp(arg, "-f")) { 3207 if (++i == argc) 3208 printUsageStatement(); 3209 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i])); 3210 continue; 3211 } 3212 if (!strcmp(arg, "-e")) { 3213 if (++i == argc) 3214 printUsageStatement(); 3215 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::CommandLine, Script::ScriptType::Script, argv[i])); 3216 continue; 3217 } 3218 if (!strcmp(arg, "-i")) { 3219 m_interactive = true; 3220 continue; 3221 } 3222 if (!strcmp(arg, "-d")) { 3223 m_dump = true; 3224 continue; 3225 } 3226 if (!strcmp(arg, "-p")) { 3227 if (++i == argc) 3228 printUsageStatement(); 3229 m_profile = true; 3230 m_profilerOutput = argv[i]; 3231 continue; 3232 } 3233 if (!strcmp(arg, "-m")) { 3234 m_module = true; 3235 continue; 3236 } 3237 if (!strcmp(arg, "-s")) { 3238 #if OS(UNIX) 3239 SignalAction (*exit)(Signal, SigInfo&, PlatformRegisters&) = [] (Signal, SigInfo&, PlatformRegisters&) { 3240 dataLogLn("Signal handler hit. Exiting with status 0"); 3241 _exit(0); 3242 return SignalAction::ForceDefault; 3243 }; 3244 3245 addSignalHandler(Signal::IllegalInstruction, SignalHandler(exit)); 3246 addSignalHandler(Signal::AccessFault, SignalHandler(exit)); 3247 addSignalHandler(Signal::FloatingPoint, SignalHandler(exit)); 3248 // once we do this lldb won't work anymore because we will exit on any breakpoints it sets. 3249 addSignalHandler(Signal::Breakpoint, SignalHandler(exit)); 3250 3251 activateSignalHandlersFor(Signal::IllegalInstruction); 3252 activateSignalHandlersFor(Signal::AccessFault); 3253 activateSignalHandlersFor(Signal::FloatingPoint); 3254 activateSignalHandlersFor(Signal::Breakpoint); 3255 3256 #if !OS(DARWIN) 3257 addSignalHandler(Signal::Abort, SignalHandler(exit)); 3258 activateSignalHandlersFor(Signal::Abort); 3259 #endif 3260 #endif 3261 continue; 3262 } 3263 if (!strcmp(arg, "-x")) { 3264 m_exitCode = true; 3265 continue; 3266 } 3267 if (!strcmp(arg, "--")) { 3268 ++i; 3269 break; 3270 } 3271 if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) 3272 printUsageStatement(true); 3273 3274 if (!strcmp(arg, "--options")) { 3275 dumpOptionsLevel = JSC::Options::DumpLevel::Verbose; 3276 needToExit = true; 3277 continue; 3278 } 3279 if (!strcmp(arg, "--dumpOptions")) { 3280 dumpOptionsLevel = JSC::Options::DumpLevel::Overridden; 3281 continue; 3282 } 3283 if (!strcmp(arg, "--sample")) { 3284 JSC::Options::useSamplingProfiler() = true; 3285 JSC::Options::collectSamplingProfilerDataForJSCShell() = true; 3286 m_dumpSamplingProfilerData = true; 3287 continue; 3288 } 3289 if (!strcmp(arg, "--destroy-vm")) { 3290 m_destroyVM = true; 3291 continue; 3292 } 3293 if (!strcmp(arg, "--can-block-is-false")) { 3294 m_canBlockIsFalse = true; 3295 continue; 3296 } 3297 if (!strcmp(arg, "--disableOptionsFreezingForTesting")) { 3298 Config::disableFreezingForTesting(); 3299 continue; 3300 } 3301 3302 static const char* timeoutMultiplierOptStr = "--timeoutMultiplier="; 3303 static const unsigned timeoutMultiplierOptStrLength = strlen(timeoutMultiplierOptStr); 3304 if (!strncmp(arg, timeoutMultiplierOptStr, timeoutMultiplierOptStrLength)) { 3305 const char* valueStr = &arg[timeoutMultiplierOptStrLength]; 3306 if (sscanf(valueStr, "%lf", &s_timeoutMultiplier) != 1) 3307 dataLog("WARNING: --timeoutMultiplier=", valueStr, " is invalid. Expects a numeric ratio.\n"); 3308 continue; 3309 } 3310 3311 if (!strcmp(arg, "--test262-async")) { 3312 asyncTestExpectedPasses++; 3313 continue; 3314 } 3315 3316 if (!strcmp(arg, "--remote-debug")) { 3317 m_enableRemoteDebugging = true; 3318 continue; 3319 } 3320 3321 static const unsigned strictFileStrLength = strlen("--strict-file="); 3322 if (!strncmp(arg, "--strict-file=", strictFileStrLength)) { 3323 m_scripts.append(Script(Script::StrictMode::Strict, Script::CodeSource::File, Script::ScriptType::Script, argv[i] + strictFileStrLength)); 3324 continue; 3325 } 3326 3327 static const unsigned moduleFileStrLength = strlen("--module-file="); 3328 if (!strncmp(arg, "--module-file=", moduleFileStrLength)) { 3329 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Module, argv[i] + moduleFileStrLength)); 3330 continue; 3331 } 3332 3333 if (!strcmp(arg, "--dumpException")) { 3334 m_alwaysDumpUncaughtException = true; 3335 continue; 3336 } 3337 3338 if (!strcmp(arg, "--footprint")) { 3339 m_dumpMemoryFootprint = true; 3340 continue; 3341 } 3342 3343 static const unsigned exceptionStrLength = strlen("--exception="); 3344 if (!strncmp(arg, "--exception=", exceptionStrLength)) { 3345 m_uncaughtExceptionName = String(arg + exceptionStrLength); 3346 continue; 3347 } 3348 3349 if (!strcmp(arg, "--watchdog-exception-ok")) { 3350 m_treatWatchdogExceptionAsSuccess = true; 3351 continue; 3352 } 3353 3354 // See if the -- option is a JSC VM option. 3355 if (strstr(arg, "--") == arg) { 3356 if (!JSC::Options::setOption(&arg[2])) { 3357 hasBadJSCOptions = true; 3358 dataLog("ERROR: invalid option: ", arg, "\n"); 3359 } 3360 continue; 3361 } 3362 3363 // This arg is not recognized by the VM nor by jsc. Pass it on to the 3364 // script. 3365 Script::ScriptType scriptType = isMJSFile(argv[i]) ? Script::ScriptType::Module : Script::ScriptType::Script; 3366 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, scriptType, argv[i])); 3367 } 3368 3369 if (hasBadJSCOptions && JSC::Options::validateOptions()) 3370 CRASH(); 3371 3372 if (m_scripts.isEmpty()) 3373 m_interactive = true; 3374 3375 for (; i < argc; ++i) 3376 m_arguments.append(argv[i]); 3377 3378 if (dumpOptionsLevel != JSC::Options::DumpLevel::None) { 3379 const char* optionsTitle = (dumpOptionsLevel == JSC::Options::DumpLevel::Overridden) 3380 ? "Modified JSC runtime options:" 3381 : "All JSC runtime options:"; 3382 JSC::Options::dumpAllOptions(stderr, dumpOptionsLevel, optionsTitle); 3383 } 3384 JSC::Options::ensureOptionsAreCoherent(); 3385 if (needToExit) 3386 jscExit(EXIT_SUCCESS); 3387 } 3388 3389 template<typename Func> 3390 int runJSC(const CommandLine& options, bool isWorker, const Func& func) 3391 { 3392 Worker worker(Workers::singleton()); 3393 3394 VM& vm = VM::create(LargeHeap).leakRef(); 3395 if (!isWorker && options.m_canBlockIsFalse) 3396 vm.m_typedArrayController = adoptRef(new JSC::SimpleTypedArrayController(false)); 3397 #if ENABLE(WEBASSEMBLY) 3398 Wasm::enableFastMemory(); 3399 #endif 3400 3401 int result; 3402 bool success = true; 3403 GlobalObject* globalObject = nullptr; 3404 { 3405 JSLockHolder locker(vm); 3406 3407 startTimeoutThreadIfNeeded(vm); 3408 if (options.m_profile && !vm.m_perBytecodeProfiler) 3409 vm.m_perBytecodeProfiler = makeUnique<Profiler::Database>(vm); 3410 3411 globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments); 3412 globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging); 3413 func(vm, globalObject, success); 3414 vm.drainMicrotasks(); 3415 } 3416 vm.deferredWorkTimer->runRunLoop(); 3417 { 3418 JSLockHolder locker(vm); 3419 if (options.m_interactive && success) 3420 runInteractive(globalObject); 3421 } 3422 3423 result = success && (asyncTestExpectedPasses == asyncTestPasses) ? 0 : 3; 3424 3425 if (options.m_exitCode) { 3426 printf("jsc exiting %d", result); 3427 if (asyncTestExpectedPasses != asyncTestPasses) 3428 printf(" because expected: %d async test passes but got: %d async test passes", asyncTestExpectedPasses, asyncTestPasses); 3429 printf("\n"); 3430 } 3431 3432 if (options.m_profile) { 3433 JSLockHolder locker(vm); 3434 if (!vm.m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data())) 3435 fprintf(stderr, "could not save profiler output.\n"); 3436 } 3437 3438 #if ENABLE(JIT) 3439 { 3440 JSLockHolder locker(vm); 3441 if (Options::useExceptionFuzz()) 3442 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks()); 3443 bool fireAtEnabled = 3444 Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter(); 3445 if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz())) 3446 printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks()); 3447 if (Options::useOSRExitFuzz() && Options::verboseOSRExitFuzz()) { 3448 printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks()); 3449 printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks()); 3450 } 3451 3452 3453 auto compileTimeStats = JIT::compileTimeStats(); 3454 Vector<CString> compileTimeKeys; 3455 for (auto& entry : compileTimeStats) 3456 compileTimeKeys.append(entry.key); 3457 std::sort(compileTimeKeys.begin(), compileTimeKeys.end()); 3458 for (const CString& key : compileTimeKeys) { 3459 if (key.data()) 3460 printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key).milliseconds()); 3461 } 3462 3463 if (Options::reportTotalPhaseTimes()) 3464 logTotalPhaseTimes(); 3465 } 3466 #endif 3467 3468 if (Options::gcAtEnd()) { 3469 // We need to hold the API lock to do a GC. 3470 JSLockHolder locker(&vm); 3471 vm.heap.collectNow(Sync, CollectionScope::Full); 3472 } 3473 3474 if (options.m_dumpSamplingProfilerData) { 3475 #if ENABLE(SAMPLING_PROFILER) 3476 JSLockHolder locker(&vm); 3477 vm.samplingProfiler()->reportTopFunctions(); 3478 vm.samplingProfiler()->reportTopBytecodes(); 3479 #else 3480 dataLog("Sampling profiler is not enabled on this platform\n"); 3481 #endif 3482 } 3483 3484 vm.codeCache()->write(vm); 3485 3486 if (options.m_destroyVM || isWorker) { 3487 JSLockHolder locker(vm); 3488 // This is needed because we don't want the worker's main 3489 // thread to die before its compilation threads finish. 3490 vm.deref(); 3491 } 3492 3493 return result; 3494 } 3495 3496 #if ENABLE(JIT_OPERATION_VALIDATION) 3497 extern const uintptr_t startOfJITOperationsInShell __asm("section$start$__DATA_CONST$__jsc_ops"); 3498 extern const uintptr_t endOfJITOperationsInShell __asm("section$end$__DATA_CONST$__jsc_ops"); 3499 #endif 3500 3501 int jscmain(int argc, char** argv) 3502 { 3503 // Need to override and enable restricted options before we start parsing options below. 3504 Config::enableRestrictedOptions(); 3505 3506 WTF::initializeMainThread(); 3507 3508 // Note that the options parsing can affect VM creation, and thus 3509 // comes first. 3510 CommandLine options(argc, argv); 3511 3512 { 3513 Options::AllowUnfinalizedAccessScope scope; 3514 processConfigFile(Options::configFile(), "jsc"); 3515 if (options.m_dump) 3516 Options::dumpGeneratedBytecodes() = true; 3517 } 3518 3519 JSC::initialize(); 3520 #if ENABLE(JIT_OPERATION_VALIDATION) 3521 JSC::JITOperationList::populatePointersInEmbedder(&startOfJITOperationsInShell, &endOfJITOperationsInShell); 3522 #endif 3523 initializeTimeoutIfNeeded(); 3524 3525 #if OS(DARWIN) || OS(LINUX) 3526 startMemoryMonitoringThreadIfNeeded(); 3527 #endif 3528 3529 if (Options::useSuperSampler()) 3530 enableSuperSampler(); 3531 3532 bool gigacageDisableRequested = false; 3533 #if GIGACAGE_ENABLED && !COMPILER(MSVC) 3534 if (char* gigacageEnabled = getenv("GIGACAGE_ENABLED")) { 3535 if (!strcasecmp(gigacageEnabled, "no") || !strcasecmp(gigacageEnabled, "false") || !strcasecmp(gigacageEnabled, "0")) 3536 gigacageDisableRequested = true; 3537 } 3538 #endif 3539 if (!gigacageDisableRequested) 3540 Gigacage::forbidDisablingPrimitiveGigacage(); 3541 3542 #if PLATFORM(COCOA) 3543 auto& memoryPressureHandler = MemoryPressureHandler::singleton(); 3544 { 3545 dispatch_queue_t queue = dispatch_queue_create("jsc shell memory pressure handler", DISPATCH_QUEUE_SERIAL); 3546 memoryPressureHandler.setDispatchQueue(queue); 3547 dispatch_release(queue); 3548 } 3549 Box<Critical> memoryPressureCriticalState = Box<Critical>::create(Critical::No); 3550 Box<Synchronous> memoryPressureSynchronousState = Box<Synchronous>::create(Synchronous::No); 3551 memoryPressureHandler.setLowMemoryHandler([=] (Critical critical, Synchronous synchronous) { 3552 crashIfExceedingMemoryLimit(); 3553 3554 // We set these racily with respect to reading them from the JS execution thread. 3555 *memoryPressureCriticalState = critical; 3556 *memoryPressureSynchronousState = synchronous; 3557 }); 3558 memoryPressureHandler.setShouldLogMemoryMemoryPressureEvents(false); 3559 memoryPressureHandler.install(); 3560 3561 auto onEachMicrotaskTick = [&] (VM& vm) { 3562 if (*memoryPressureCriticalState == Critical::No) 3563 return; 3564 3565 *memoryPressureCriticalState = Critical::No; 3566 bool isSynchronous = *memoryPressureSynchronousState == Synchronous::Yes; 3567 3568 WTF::releaseFastMallocFreeMemory(); 3569 vm.deleteAllCode(DeleteAllCodeIfNotCollecting); 3570 3571 if (!vm.heap.isCurrentThreadBusy()) { 3572 if (isSynchronous) { 3573 vm.heap.collectNow(Sync, CollectionScope::Full); 3574 WTF::releaseFastMallocFreeMemory(); 3575 } else 3576 vm.heap.collectNowFullIfNotDoneRecently(Async); 3577 } 3578 }; 3579 #endif 3580 3581 int result = runJSC( 3582 options, false, 3583 [&] (VM& vm, GlobalObject* globalObject, bool& success) { 3584 UNUSED_PARAM(vm); 3585 #if PLATFORM(COCOA) 3586 vm.setOnEachMicrotaskTick(WTFMove(onEachMicrotaskTick)); 3587 #endif 3588 runWithOptions(globalObject, options, success); 3589 }); 3590 3591 printSuperSamplerState(); 3592 3593 if (options.m_dumpMemoryFootprint) { 3594 MemoryFootprint footprint = MemoryFootprint::now(); 3595 3596 printf("Memory Footprint:\n Current Footprint: %" PRIu64 "\n Peak Footprint: %" PRIu64 "\n", footprint.current, footprint.peak); 3597 } 3598 3599 return result; 3600 } 3601 3602 #if OS(WINDOWS) 3603 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]) 3604 { 3605 return main(argc, const_cast<char**>(argv)); 3606 } 3607 #endif