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

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

[JSC] Lock-down JSGlobalObject and derived classes in IsoSubspace
https://bugs.webkit.org/show_bug.cgi?id=205108

Reviewed by Mark Lam.

Source/JavaScriptCore:

This patch puts JSGlobalLexicalEnvironment and JSGlobalObject (and its derived classes including JSDOMWindow etc.) in IsoSubspace.
We were using addFinalizer feature to call destructors for these objects since they do not inherit JSDestructibleObject. But now
each derived classes has its IsoSubspace. So we do not need to use finalizer feature: just setting specialized HeapCellType works.

  • API/JSAPIGlobalObject.h:
  • API/JSCallbackObject.cpp:
  • API/glib/JSAPIWrapperGlobalObject.cpp:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/SuperSampler.h:
  • heap/CellAttributes.h:
  • heap/FreeList.h:
  • heap/IsoHeapCellType.cpp:

(JSC::IsoHeapCellType::IsoHeapCellType):

  • heap/IsoHeapCellType.h:
  • heap/MarkedBlock.cpp:

(JSC::MarkedBlock::Handle::setIsFreeListed): Deleted.

  • heap/MarkedBlockInlines.h:

(JSC::MarkedBlock::Handle::setIsFreeListed):

  • jsc.cpp:

(GlobalObject::create): Deleted.
(GlobalObject::createStructure): Deleted.
(GlobalObject::javaScriptRuntimeFlags): Deleted.
(GlobalObject::finishCreation): Deleted.
(GlobalObject::addFunction): Deleted.

  • runtime/JSGlobalLexicalEnvironment.h:
  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::subspaceFor):

  • runtime/JSSegmentedVariableObject.cpp:

(JSC::JSSegmentedVariableObject::JSSegmentedVariableObject):
(JSC::JSSegmentedVariableObject::finishCreation):
(JSC::JSSegmentedVariableObject::destroy): Deleted.

  • runtime/JSSegmentedVariableObject.h:

(JSC::JSSegmentedVariableObject::subspaceFor):
(JSC::JSSegmentedVariableObject::classInfo const): Deleted.

  • runtime/VM.cpp:

(JSC::VM::VM):

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

(GlobalObject::create): Deleted.
(GlobalObject::createStructure): Deleted.
(GlobalObject::finishCreation): Deleted.

Source/WebCore:

We put derived classes of JSGlobalObject in IsoSubspace in WebCore side too.

  • bindings/js/JSDOMGlobalObject.h:
  • bindings/js/JSDOMWindowBase.h:
  • bindings/js/JSDOMWrapper.cpp:

(WebCore::globalObjectOutputConstraintSubspaceFor): Deleted.

  • bindings/js/JSDOMWrapper.h:
  • bindings/js/JSRemoteDOMWindowBase.h:
  • bindings/js/JSWindowProxy.h:
  • bindings/js/JSWorkerGlobalScopeBase.h:

(WebCore::JSWorkerGlobalScopeBase::subspaceFor):

  • bindings/js/JSWorkletGlobalScopeBase.h:

(WebCore::JSWorkletGlobalScopeBase::subspaceFor):

  • bindings/js/WebCoreJSClientData.cpp:

(WebCore::JSVMClientData::JSVMClientData):

  • bindings/js/WebCoreJSClientData.h:

(WebCore::JSVMClientData::subspaceForJSDOMWindow):
(WebCore::JSVMClientData::subspaceForJSDedicatedWorkerGlobalScope):
(WebCore::JSVMClientData::subspaceForJSRemoteDOMWindow):
(WebCore::JSVMClientData::subspaceForJSWorkerGlobalScope):
(WebCore::JSVMClientData::subspaceForJSServiceWorkerGlobalScope):
(WebCore::JSVMClientData::subspaceForJSPaintWorkletGlobalScope):
(WebCore::JSVMClientData::subspaceForJSWorkletGlobalScope):
(WebCore::JSVMClientData::forEachOutputConstraintSpace):
(WebCore::JSVMClientData::globalObjectOutputConstraintSpace): Deleted.

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateHeader):
(GenerateImplementation):
(GeneratePrototypeDeclaration):

  • bindings/scripts/test/JS/JSInterfaceName.cpp:
  • bindings/scripts/test/JS/JSMapLike.cpp:
  • bindings/scripts/test/JS/JSReadOnlyMapLike.cpp:
  • bindings/scripts/test/JS/JSReadOnlySetLike.cpp:
  • bindings/scripts/test/JS/JSSetLike.cpp:
  • bindings/scripts/test/JS/JSTestActiveDOMObject.cpp:
  • bindings/scripts/test/JS/JSTestCEReactions.cpp:
  • bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp:
  • bindings/scripts/test/JS/JSTestCallTracer.cpp:
  • bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp:
  • bindings/scripts/test/JS/JSTestDOMJIT.cpp:
  • bindings/scripts/test/JS/JSTestEnabledBySetting.cpp:
  • bindings/scripts/test/JS/JSTestEnabledForContext.cpp:
  • bindings/scripts/test/JS/JSTestEventConstructor.cpp:
  • bindings/scripts/test/JS/JSTestEventTarget.cpp:
  • bindings/scripts/test/JS/JSTestException.cpp:
  • bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp:
  • bindings/scripts/test/JS/JSTestGlobalObject.cpp:

(WebCore::JSTestGlobalObject::subspaceForImpl):

  • bindings/scripts/test/JS/JSTestGlobalObject.h:

(WebCore::JSTestGlobalObject::subspaceFor):

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