source: webkit/trunk/Source/JavaScriptCore/jsc.cpp@ 289863

Last change on this file since 289863 was 289863, checked in by [email protected], 3 years ago

Make HeapType an enum class.
https://bugs.webkit.org/show_bug.cgi?id=236667
<rdar://problem/88984607>

Reviewed by Yusuke Suzuki.

Source/JavaScriptCore:

  • dynbench.cpp:
  • heap/Heap.cpp:
  • heap/Heap.h:
  • jsc.cpp:

(runJSC):

  • runtime/VM.cpp:

(JSC::VM::sharedInstance):

  • runtime/VM.h:
  • testRegExp.cpp:

(realMain):

Source/WebCore:

  • bindings/js/CommonVM.cpp:

(WebCore::commonVMSlow):

Tools:

  • TestWebKitAPI/Tests/JavaScriptCore/DisallowVMEntry.cpp:

(TestWebKitAPI::TEST):

  • TestWebKitAPI/Tests/JavaScriptCore/PropertySlot.cpp:

(TestWebKitAPI::TEST):

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