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

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

Rollout r240210: It broke tests on iOS
https://bugs.webkit.org/show_bug.cgi?id=193640

Source/JavaScriptCore:

Unreviewed. ~2650 tests are failing on iOS.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • builtins/BuiltinNames.cpp:

(JSC::BuiltinNames::BuiltinNames):

  • builtins/BuiltinNames.h:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::setConstantIdentifierSetRegisters):

  • bytecode/CodeBlock.h:
  • bytecode/HandlerInfo.h:
  • bytecode/InstructionStream.h:
  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::addSetConstant):
(JSC::UnlinkedCodeBlock::constantIdentifierSets):

  • bytecode/UnlinkedEvalCodeBlock.h:
  • bytecode/UnlinkedFunctionCodeBlock.h:
  • bytecode/UnlinkedFunctionExecutable.h:
  • bytecode/UnlinkedGlobalCodeBlock.h:

(JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock):

  • bytecode/UnlinkedMetadataTable.h:
  • bytecode/UnlinkedModuleProgramCodeBlock.h:
  • bytecode/UnlinkedProgramCodeBlock.h:
  • interpreter/Interpreter.cpp:
  • jsc.cpp:

(functionQuit):
(runJSC):

  • parser/SourceCode.h:
  • parser/SourceCodeKey.h:

(JSC::SourceCodeKey::operator!= const): Deleted.

  • parser/UnlinkedSourceCode.h:
  • parser/VariableEnvironment.h:
  • runtime/CachedTypes.cpp:

(): Deleted.
(JSC::Encoder::Allocation::buffer const): Deleted.
(JSC::Encoder::Allocation::offset const): Deleted.
(JSC::Encoder::Allocation::Allocation): Deleted.
(JSC::Encoder::Encoder): Deleted.
(JSC::Encoder::vm): Deleted.
(JSC::Encoder::malloc): Deleted.
(JSC::Encoder::offsetOf): Deleted.
(JSC::Encoder::cachePtr): Deleted.
(JSC::Encoder::offsetForPtr): Deleted.
(JSC::Encoder::release): Deleted.
(JSC::Encoder::Page::Page): Deleted.
(JSC::Encoder::Page::malloc): Deleted.
(JSC::Encoder::Page::buffer const): Deleted.
(JSC::Encoder::Page::size const): Deleted.
(JSC::Encoder::Page::getOffset const): Deleted.
(JSC::Encoder::allocateNewPage): Deleted.
(JSC::Decoder::Decoder): Deleted.
(JSC::Decoder::~Decoder): Deleted.
(JSC::Decoder::vm): Deleted.
(JSC::Decoder::offsetOf): Deleted.
(JSC::Decoder::cacheOffset): Deleted.
(JSC::Decoder::addFinalizer): Deleted.
(JSC::encode): Deleted.
(JSC::decode): Deleted.
(JSC::VariableLengthObject::buffer const): Deleted.
(JSC::VariableLengthObject::allocate): Deleted.
(JSC::CachedPtr::encode): Deleted.
(JSC::CachedPtr::decode const): Deleted.
(JSC::CachedPtr::operator-> const): Deleted.
(JSC::CachedPtr::get const): Deleted.
(JSC::CachedRefPtr::encode): Deleted.
(JSC::CachedRefPtr::decode const): Deleted.
(JSC::CachedWriteBarrier::encode): Deleted.
(JSC::CachedWriteBarrier::decode const): Deleted.
(JSC::CachedVector::encode): Deleted.
(JSC::CachedVector::decode const): Deleted.
(JSC::CachedPair::encode): Deleted.
(JSC::CachedPair::decode const): Deleted.
(JSC::CachedHashMap::encode): Deleted.
(JSC::CachedHashMap::decode const): Deleted.
(JSC::CachedUniquedStringImpl::encode): Deleted.
(JSC::CachedUniquedStringImpl::decode const): Deleted.
(JSC::CachedStringImpl::encode): Deleted.
(JSC::CachedStringImpl::decode const): Deleted.
(JSC::CachedString::encode): Deleted.
(JSC::CachedString::decode const): Deleted.
(JSC::CachedIdentifier::encode): Deleted.
(JSC::CachedIdentifier::decode const): Deleted.
(JSC::CachedOptional::encode): Deleted.
(JSC::CachedOptional::decode const): Deleted.
(JSC::CachedOptional::decodeAsPtr const): Deleted.
(JSC::CachedSimpleJumpTable::encode): Deleted.
(JSC::CachedSimpleJumpTable::decode const): Deleted.
(JSC::CachedStringJumpTable::encode): Deleted.
(JSC::CachedStringJumpTable::decode const): Deleted.
(JSC::CachedCodeBlockRareData::encode): Deleted.
(JSC::CachedCodeBlockRareData::decode const): Deleted.
(JSC::CachedBitVector::encode): Deleted.
(JSC::CachedBitVector::decode const): Deleted.
(JSC::CachedHashSet::encode): Deleted.
(JSC::CachedHashSet::decode const): Deleted.
(JSC::CachedConstantIdentifierSetEntry::encode): Deleted.
(JSC::CachedConstantIdentifierSetEntry::decode const): Deleted.
(JSC::CachedVariableEnvironment::encode): Deleted.
(JSC::CachedVariableEnvironment::decode const): Deleted.
(JSC::CachedArray::encode): Deleted.
(JSC::CachedArray::decode const): Deleted.
(JSC::CachedScopedArgumentsTable::encode): Deleted.
(JSC::CachedScopedArgumentsTable::decode const): Deleted.
(JSC::CachedSymbolTableEntry::encode): Deleted.
(JSC::CachedSymbolTableEntry::decode const): Deleted.
(JSC::CachedSymbolTable::encode): Deleted.
(JSC::CachedSymbolTable::decode const): Deleted.
(JSC::CachedImmutableButterfly::encode): Deleted.
(JSC::CachedImmutableButterfly::decode const): Deleted.
(JSC::CachedRegExp::encode): Deleted.
(JSC::CachedRegExp::decode const): Deleted.
(JSC::CachedTemplateObjectDescriptor::encode): Deleted.
(JSC::CachedTemplateObjectDescriptor::decode const): Deleted.
(JSC::CachedBigInt::encode): Deleted.
(JSC::CachedBigInt::decode const): Deleted.
(JSC::CachedJSValue::encode): Deleted.
(JSC::CachedJSValue::decode const): Deleted.
(JSC::CachedInstructionStream::encode): Deleted.
(JSC::CachedInstructionStream::decode const): Deleted.
(JSC::CachedMetadataTable::encode): Deleted.
(JSC::CachedMetadataTable::decode const): Deleted.
(JSC::CachedSourceOrigin::encode): Deleted.
(JSC::CachedSourceOrigin::decode const): Deleted.
(JSC::CachedTextPosition::encode): Deleted.
(JSC::CachedTextPosition::decode const): Deleted.
(JSC::CachedSourceProviderShape::encode): Deleted.
(JSC::CachedSourceProviderShape::decode const): Deleted.
(JSC::CachedStringSourceProvider::encode): Deleted.
(JSC::CachedStringSourceProvider::decode const): Deleted.
(JSC::CachedWebAssemblySourceProvider::encode): Deleted.
(JSC::CachedWebAssemblySourceProvider::decode const): Deleted.
(JSC::CachedSourceProvider::encode): Deleted.
(JSC::CachedSourceProvider::decode const): Deleted.
(JSC::CachedUnlinkedSourceCodeShape::encode): Deleted.
(JSC::CachedUnlinkedSourceCodeShape::decode const): Deleted.
(JSC::CachedSourceCode::encode): Deleted.
(JSC::CachedSourceCode::decode const): Deleted.
(JSC::CachedFunctionExecutable::firstLineOffset const): Deleted.
(JSC::CachedFunctionExecutable::lineCount const): Deleted.
(JSC::CachedFunctionExecutable::unlinkedFunctionNameStart const): Deleted.
(JSC::CachedFunctionExecutable::unlinkedBodyStartColumn const): Deleted.
(JSC::CachedFunctionExecutable::unlinkedBodyEndColumn const): Deleted.
(JSC::CachedFunctionExecutable::startOffset const): Deleted.
(JSC::CachedFunctionExecutable::sourceLength const): Deleted.
(JSC::CachedFunctionExecutable::parametersStartOffset const): Deleted.
(JSC::CachedFunctionExecutable::typeProfilingStartOffset const): Deleted.
(JSC::CachedFunctionExecutable::typeProfilingEndOffset const): Deleted.
(JSC::CachedFunctionExecutable::parameterCount const): Deleted.
(JSC::CachedFunctionExecutable::features const): Deleted.
(JSC::CachedFunctionExecutable::sourceParseMode const): Deleted.
(JSC::CachedFunctionExecutable::isInStrictContext const): Deleted.
(JSC::CachedFunctionExecutable::hasCapturedVariables const): Deleted.
(JSC::CachedFunctionExecutable::isBuiltinFunction const): Deleted.
(JSC::CachedFunctionExecutable::isBuiltinDefaultClassConstructor const): Deleted.
(JSC::CachedFunctionExecutable::constructAbility const): Deleted.
(JSC::CachedFunctionExecutable::constructorKind const): Deleted.
(JSC::CachedFunctionExecutable::functionMode const): Deleted.
(JSC::CachedFunctionExecutable::scriptMode const): Deleted.
(JSC::CachedFunctionExecutable::superBinding const): Deleted.
(JSC::CachedFunctionExecutable::derivedContextType const): Deleted.
(JSC::CachedFunctionExecutable::name const): Deleted.
(JSC::CachedFunctionExecutable::ecmaName const): Deleted.
(JSC::CachedFunctionExecutable::inferredName const): Deleted.
(JSC::CachedCodeBlock::instructions const): Deleted.
(JSC::CachedCodeBlock::thisRegister const): Deleted.
(JSC::CachedCodeBlock::scopeRegister const): Deleted.
(JSC::CachedCodeBlock::globalObjectRegister const): Deleted.
(JSC::CachedCodeBlock::sourceURLDirective const): Deleted.
(JSC::CachedCodeBlock::sourceMappingURLDirective const): Deleted.
(JSC::CachedCodeBlock::usesEval const): Deleted.
(JSC::CachedCodeBlock::isStrictMode const): Deleted.
(JSC::CachedCodeBlock::isConstructor const): Deleted.
(JSC::CachedCodeBlock::hasCapturedVariables const): Deleted.
(JSC::CachedCodeBlock::isBuiltinFunction const): Deleted.
(JSC::CachedCodeBlock::superBinding const): Deleted.
(JSC::CachedCodeBlock::scriptMode const): Deleted.
(JSC::CachedCodeBlock::isArrowFunctionContext const): Deleted.
(JSC::CachedCodeBlock::isClassContext const): Deleted.
(JSC::CachedCodeBlock::wasCompiledWithDebuggingOpcodes const): Deleted.
(JSC::CachedCodeBlock::constructorKind const): Deleted.
(JSC::CachedCodeBlock::derivedContextType const): Deleted.
(JSC::CachedCodeBlock::evalContextType const): Deleted.
(JSC::CachedCodeBlock::hasTailCalls const): Deleted.
(JSC::CachedCodeBlock::lineCount const): Deleted.
(JSC::CachedCodeBlock::endColumn const): Deleted.
(JSC::CachedCodeBlock::numVars const): Deleted.
(JSC::CachedCodeBlock::numCalleeLocals const): Deleted.
(JSC::CachedCodeBlock::numParameters const): Deleted.
(JSC::CachedCodeBlock::features const): Deleted.
(JSC::CachedCodeBlock::parseMode const): Deleted.
(JSC::CachedCodeBlock::codeType const): Deleted.
(JSC::CachedCodeBlock::rareData const): Deleted.
(JSC::CachedProgramCodeBlock::encode): Deleted.
(JSC::CachedProgramCodeBlock::decode const): Deleted.
(JSC::CachedModuleCodeBlock::encode): Deleted.
(JSC::CachedModuleCodeBlock::decode const): Deleted.
(JSC::CachedEvalCodeBlock::encode): Deleted.
(JSC::CachedEvalCodeBlock::decode const): Deleted.
(JSC::CachedFunctionCodeBlock::encode): Deleted.
(JSC::CachedFunctionCodeBlock::decode const): Deleted.
(JSC::UnlinkedFunctionCodeBlock::UnlinkedFunctionCodeBlock): Deleted.
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): Deleted.
(JSC::CachedCodeBlock<CodeBlockType>::decode const): Deleted.
(JSC::UnlinkedProgramCodeBlock::UnlinkedProgramCodeBlock): Deleted.
(JSC::UnlinkedModuleProgramCodeBlock::UnlinkedModuleProgramCodeBlock): Deleted.
(JSC::UnlinkedEvalCodeBlock::UnlinkedEvalCodeBlock): Deleted.
(JSC::CachedFunctionExecutable::encode): Deleted.
(JSC::CachedFunctionExecutable::decode const): Deleted.
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): Deleted.
(JSC::CachedCodeBlock<CodeBlockType>::encode): Deleted.
(JSC::CachedSourceCodeKey::encode): Deleted.
(JSC::CachedSourceCodeKey::decode const): Deleted.
(JSC::CacheEntry::encode): Deleted.
(JSC::CacheEntry:: const): Deleted.
(JSC:: const): Deleted.
(JSC::encodeCodeBlock): Deleted.
(JSC::decodeCodeBlockImpl): Deleted.

  • runtime/CachedTypes.h:

(JSC::decodeCodeBlock): Deleted.

  • runtime/CodeCache.cpp:

(JSC::CodeCacheMap::pruneSlowCase):
(JSC::CodeCache::getUnlinkedGlobalCodeBlock):
(JSC::CodeCache::getUnlinkedGlobalFunctionExecutable):
(JSC::CodeCache::write): Deleted.

  • runtime/CodeCache.h:

(JSC::CodeCacheMap::findCacheAndUpdateAge):
(JSC::CodeCache::clear):
(JSC::CodeCacheMap::begin): Deleted.
(JSC::CodeCacheMap::end): Deleted.
(JSC::CodeCacheMap::fetchFromDiskImpl): Deleted.
(): Deleted.
(JSC::writeCodeBlock): Deleted.

  • runtime/JSBigInt.cpp:

(JSC::JSBigInt::offsetOfData):
(JSC::JSBigInt::dataStorage):

  • runtime/JSBigInt.h:
  • runtime/Options.cpp:

(JSC::recomputeDependentOptions):

  • runtime/Options.h:
  • runtime/RegExp.h:
  • runtime/ScopedArgumentsTable.h:
  • runtime/StackFrame.h:
  • runtime/StructureInlines.h:
  • runtime/SymbolTable.h:

Source/WTF:

Unreviewed.

  • wtf/BitVector.h:

Tools:

Unreviewed.

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