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

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

Enhance Options::useOSLog to accept an os log type value.
https://bugs.webkit.org/show_bug.cgi?id=241719

Reviewed by Yusuke Suzuki.

This option only applies to OS(DARWIN).

For example, we can now use any of these:

--useOSLog=default logs to OS_LOG_TYPE_DEFAULT
--useOSLog=info
logs to OS_LOG_TYPE_INFO
--useOSLog=debug logs to OS_LOG_TYPE_DEBUG
--useOSLog=error
logs to OS_LOG_TYPE_ERROR
--useOSLog=fault. logs to OS_LOG_TYPE_FAULT

We can still use --useOSLog=0 or false (which means do the normal dataLog) and
--useOSLog=1 or true (which means dataLog to OS_LOG_TYPE_ERROR).

Previously, when we specify --useOSLog=1, we will log to OS_LOG_TYPE_INFO. This
has been a source of friction in usage because no one ever remembers that we need
to enable OS_LOG_TYPE_INFO in the log stream to see this logging. Instead,
--useOSLog=1 will now log to OS_LOG_TYPE_ERROR, which ensures that logging will
show up in log stream. This is fine to do because the --useOSLog=1 option
indicates that the client really wants to see the logs. Otherwise, the client
can use one of the other os log types if they want something different.

Secondly, because --useOSLog=1 indicates that the client really wants to see the
logs, logging to OS_LOG_TYPE_ERROR ensures that the logging is flushed to the
file system instead of sitting in a memory buffer, and potentially not showing up
in the log stream.

Also made the following changes:

  1. Changed Options::dumpAllOptions to use dataLog instead of printing to stderr. This allows its output to be diverted using Options::useOSLog as well.
  1. Moved the call to WTF::setDataFile from Options::initialize to Options::recomputeDependentOptions. This allows Options::useOSLog to be specified using the jsc shell's --useOSLog argument instead of requiring it to be specified using the JSC_useOSLog env var in order to work.

To enable this, added a useOSLogOptionHasChanged flag that can be set in
the parser of the Options::useOSLog option. This prevents
Options::recomputeDependentOptions from calling initializeDatafileToUseOSLog()
repeatedly every time any option is set.

  1. Added initializeDatafileToUseOSLog() which now instantiates the appropriate OSLogPrintStream and sets it using WTF::setDataFile.

initializeDatafileToUseOSLog() also asserts that it is called at most once.

  1. Added an assertion in WTF::setDataFile() to ensure that it is not called more than once.
  1. #if out the calls to overrideAliasedOptionWithHeuristic() on PLATFORM(COCOA). They are not needed because, on PLATFORM(COCOA), we already iterate through every env var starting with JSC_ and call Options::setOption() on it. Options::setOption() will also handle aliased options.

For reference, this is an example of how we can view the logs using log stream
once --useOSLog=1 is used:

# log stream --predicate 'category == "DataLog"'

  • Source/JavaScriptCore/API/glib/JSCOptions.cpp:
  • Source/JavaScriptCore/jsc.cpp:

(CommandLine::parseArguments):

  • Source/JavaScriptCore/runtime/Options.cpp:

(JSC::parse):
(JSC::asDarwinOSLogType):
(JSC::initializeDatafileToUseOSLog):
(JSC::asString):
(JSC::Options::recomputeDependentOptions):
(JSC::Options::initialize):
(JSC::Options::setOptionWithoutAlias):
(JSC::Options::dumpAllOptions):
(JSC::OptionReader::Option::initValue):
(JSC::OptionReader::Option::dump const):
(JSC::OptionReader::Option::operator== const):

  • Source/JavaScriptCore/runtime/Options.h:
  • Source/JavaScriptCore/runtime/OptionsList.h:
  • Source/WTF/wtf/DataLog.cpp:

(WTF::setDataFile):

Canonical link: https://commits.webkit.org/251661@main

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