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