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

Last change on this file since 229092 was 229092, checked in by Yusuke Suzuki, 7 years ago

JSC crash with import("")
https://bugs.webkit.org/show_bug.cgi?id=183175

Reviewed by Saam Barati.

JSTests:

  • stress/import-with-empty-string.js: Added.

Source/JavaScriptCore:

Add file existence and file type check for module loader implementation in jsc.cpp.
This is not safe for TOCTOU, but it is OK since this functionality is used for the
JSC shell (jsc.cpp): testing purpose.

  • jsc.cpp:

(fillBufferWithContentsOfFile):
(fetchModuleFromLocalFileSystem):

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