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

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

LLInt should loop OSR into BBQ and BBQ should loop OSR into OMG
https://bugs.webkit.org/show_bug.cgi?id=234542

Reviewed by Yusuke Suzuki.

JSTests:

  • wasm/wast-tests/harness.js:

Source/JavaScriptCore:

It's a startup perf improvement on some Wasm benchmarks I'm running to have
Wasm LLInt do loop OSR entry into BBQ instead of OMG. This improves this
benchmark by 5%. There is probably more perf to be had here. Currently,
we're just OSR entering into B3 BBQ O1. However, in the future, we should
just compile a single Air BBQ Callee that allows for OSR entry at loop
boundaries. Maybe we can model this using EntrySwitch without any real
harm to throughput.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • assembler/MacroAssemblerCodeRef.cpp:

(JSC::shouldDumpDisassemblyFor):

  • jsc.cpp:

(JSC_DEFINE_HOST_FUNCTION):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::parseAndCompile):

  • wasm/WasmCallee.h:

(JSC::Wasm::Callee::setOSREntryCallee): Deleted.

  • wasm/WasmCalleeGroup.h:
  • wasm/WasmCompilationMode.cpp:

(JSC::Wasm::makeString):

  • wasm/WasmCompilationMode.h:

(JSC::Wasm::isOSREntry):
(JSC::Wasm::isAnyBBQ):
(JSC::Wasm::isAnyOMG):

  • wasm/WasmOMGForOSREntryPlan.cpp: Removed.
  • wasm/WasmOMGForOSREntryPlan.h: Removed.
  • wasm/WasmOSREntryPlan.cpp: Copied from Source/JavaScriptCore/wasm/WasmOMGForOSREntryPlan.cpp.

(JSC::Wasm::OSREntryPlan::OSREntryPlan):
(JSC::Wasm::OSREntryPlan::work):
(JSC::Wasm::OMGForOSREntryPlan::OMGForOSREntryPlan): Deleted.
(JSC::Wasm::OMGForOSREntryPlan::work): Deleted.

  • wasm/WasmOSREntryPlan.h: Copied from Source/JavaScriptCore/wasm/WasmOMGForOSREntryPlan.h.
  • wasm/WasmOperations.cpp:

(JSC::Wasm::doOSREntry):
(JSC::Wasm::JSC_DEFINE_JIT_OPERATION):

  • wasm/WasmPlan.cpp:

(JSC::Wasm::Plan::updateCallSitesToCallUs):

  • wasm/WasmSlowPaths.cpp:

(JSC::LLInt::WASM_SLOW_PATH_DECL):

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