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

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

[JSC] Add inherits<T>(VM&) leveraging JSCast fast path
https://bugs.webkit.org/show_bug.cgi?id=183429

Reviewed by Mark Lam.

Source/JavaScriptCore:

Add new member function, JSCell::inherits<T>(VM&) and JSValue::inherits<T>(VM&).
They depends on jsDynamicCast<T> implementation and leverage JSType-based fast
paths defined in JSCast.h. We extract checking part as JSCastingHelpers::inherit
and construct jsDynamicCast and JSCell::inherits based on this.

And we remove several unnecessary casting functions (asRegExpObject, asDateInstance etc.).
In addition, we add jsDynamicCast fast path for RegExpObject by using existing RegExpObjectType.

We also fix the implementation of jsDynamicCast for JSObject since it uses LastJSCObjectType.
The embedder can add their extended object types after that.

  • API/JSObjectRef.cpp:

(JSObjectGetPrivateProperty):
(JSObjectSetPrivateProperty):
(JSObjectDeletePrivateProperty):

  • API/JSValue.mm:

(isDate):
(isArray):

  • API/JSValueRef.cpp:

(JSValueIsArray):
(JSValueIsDate):
(JSValueIsObjectOfClass):

  • API/JSWeakObjectMapRefPrivate.cpp:
  • API/JSWrapperMap.mm:

(tryUnwrapObjcObject):

  • API/ObjCCallbackFunction.mm:

(tryUnwrapConstructor):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGOperations.cpp:
  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileOverridesHasInstance):
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):

  • ftl/FTLOperations.cpp:

(JSC::FTL::operationMaterializeObjectInOSR):

  • inspector/JSInjectedScriptHost.cpp:

(Inspector::JSInjectedScriptHost::subtype):
(Inspector::JSInjectedScriptHost::functionDetails):

  • inspector/agents/InspectorHeapAgent.cpp:

(Inspector::InspectorHeapAgent::getPreview):

  • interpreter/Interpreter.cpp:

(JSC::notifyDebuggerOfUnwinding):

  • interpreter/ShadowChicken.cpp:

(JSC::ShadowChicken::update):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JITOperations.cpp:

(JSC::operationNewFunctionCommon):

  • jsc.cpp:

(checkException):

  • runtime/BooleanObject.h:

(JSC::asBooleanObject): Deleted.

  • runtime/BooleanPrototype.cpp:

(JSC::booleanProtoFuncToString):
(JSC::booleanProtoFuncValueOf):

  • runtime/DateConstructor.cpp:

(JSC::constructDate):

  • runtime/DateInstance.h:

(JSC::asDateInstance): Deleted.

  • runtime/DatePrototype.cpp:

(JSC::formateDateInstance):
(JSC::dateProtoFuncToISOString):
(JSC::dateProtoFuncToLocaleString):
(JSC::dateProtoFuncToLocaleDateString):
(JSC::dateProtoFuncToLocaleTimeString):
(JSC::dateProtoFuncGetTime):
(JSC::dateProtoFuncGetFullYear):
(JSC::dateProtoFuncGetUTCFullYear):
(JSC::dateProtoFuncGetMonth):
(JSC::dateProtoFuncGetUTCMonth):
(JSC::dateProtoFuncGetDate):
(JSC::dateProtoFuncGetUTCDate):
(JSC::dateProtoFuncGetDay):
(JSC::dateProtoFuncGetUTCDay):
(JSC::dateProtoFuncGetHours):
(JSC::dateProtoFuncGetUTCHours):
(JSC::dateProtoFuncGetMinutes):
(JSC::dateProtoFuncGetUTCMinutes):
(JSC::dateProtoFuncGetSeconds):
(JSC::dateProtoFuncGetUTCSeconds):
(JSC::dateProtoFuncGetMilliSeconds):
(JSC::dateProtoFuncGetUTCMilliseconds):
(JSC::dateProtoFuncGetTimezoneOffset):
(JSC::dateProtoFuncSetTime):
(JSC::setNewValueFromTimeArgs):
(JSC::setNewValueFromDateArgs):
(JSC::dateProtoFuncSetYear):
(JSC::dateProtoFuncGetYear):

  • runtime/ExceptionHelpers.cpp:

(JSC::isTerminatedExecutionException):

  • runtime/FunctionPrototype.cpp:

(JSC::functionProtoFuncToString):

  • runtime/InternalFunction.h:

(JSC::asInternalFunction):

  • runtime/JSArray.h:

(JSC::asArray):

  • runtime/JSCJSValue.cpp:

(JSC::JSValue::dumpForBacktrace const):

  • runtime/JSCJSValue.h:
  • runtime/JSCJSValueInlines.h:

(JSC::JSValue::inherits const):

  • runtime/JSCast.h:

(JSC::JSCastingHelpers::inheritsGenericImpl):
(JSC::JSCastingHelpers::inheritsJSTypeImpl):
(JSC::JSCastingHelpers::InheritsTraits::inherits):
(JSC::JSCastingHelpers::inherits):
(JSC::jsDynamicCast):
(JSC::JSCastingHelpers::jsDynamicCastGenericImpl): Deleted.
(JSC::JSCastingHelpers::jsDynamicCastJSTypeImpl): Deleted.
(JSC::JSCastingHelpers::JSDynamicCastTraits::cast): Deleted.

  • runtime/JSCell.h:
  • runtime/JSCellInlines.h:

(JSC::JSCell::inherits const):

  • runtime/JSFunction.cpp:

(JSC::RetrieveCallerFunctionFunctor::operator() const):
(JSC::JSFunction::callerGetter):
(JSC::JSFunction::getOwnNonIndexPropertyNames):
(JSC::JSFunction::reifyLazyBoundNameIfNeeded):

  • runtime/JSGlobalObject.cpp:

(JSC::enqueueJob):

  • runtime/JSGlobalObject.h:

(JSC::asGlobalObject): Deleted.

  • runtime/JSInternalPromiseDeferred.cpp:

(JSC::JSInternalPromiseDeferred::create):

  • runtime/JSLexicalEnvironment.h:

(JSC::asActivation):

  • runtime/JSONObject.cpp:

(JSC::unwrapBoxedPrimitive):
(JSC::Stringifier::Stringifier):
(JSC::Walker::walk):

  • runtime/JSPromise.cpp:

(JSC::JSPromise::resolve):

  • runtime/JSPromiseDeferred.cpp:

(JSC::JSPromiseDeferred::create):

  • runtime/JSType.h:
  • runtime/ProxyObject.h:

(JSC::ProxyObject::create): Deleted.
(JSC::ProxyObject::createStructure): Deleted.
(JSC::ProxyObject::target const): Deleted.
(JSC::ProxyObject::handler const): Deleted.

  • runtime/RegExpConstructor.cpp:

(JSC::constructRegExp):

  • runtime/RegExpConstructor.h:

(JSC::asRegExpConstructor):
(JSC::isRegExp):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::finishCreation):
(JSC::RegExpObject::getOwnPropertySlot):
(JSC::RegExpObject::defineOwnProperty):
(JSC::regExpObjectSetLastIndexStrict):
(JSC::regExpObjectSetLastIndexNonStrict):
(JSC::RegExpObject::put):

  • runtime/RegExpObject.h:

(JSC::RegExpObject::create): Deleted.
(JSC::RegExpObject::setRegExp): Deleted.
(JSC::RegExpObject::regExp const): Deleted.
(JSC::RegExpObject::setLastIndex): Deleted.
(JSC::RegExpObject::getLastIndex const): Deleted.
(JSC::RegExpObject::test): Deleted.
(JSC::RegExpObject::testInline): Deleted.
(JSC::RegExpObject::createStructure): Deleted.
(JSC::RegExpObject::offsetOfRegExp): Deleted.
(JSC::RegExpObject::offsetOfLastIndex): Deleted.
(JSC::RegExpObject::offsetOfLastIndexIsWritable): Deleted.
(JSC::RegExpObject::allocationSize): Deleted.
(JSC::asRegExpObject): Deleted.

  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoFuncTestFast):
(JSC::regExpProtoFuncExec):
(JSC::regExpProtoFuncMatchFast):
(JSC::regExpProtoFuncCompile):
(JSC::regExpProtoGetterGlobal):
(JSC::regExpProtoGetterIgnoreCase):
(JSC::regExpProtoGetterMultiline):
(JSC::regExpProtoGetterDotAll):
(JSC::regExpProtoGetterSticky):
(JSC::regExpProtoGetterUnicode):
(JSC::regExpProtoGetterSource):
(JSC::regExpProtoFuncSearchFast):
(JSC::regExpProtoFuncSplitFast):

  • runtime/StringObject.h:

(JSC::asStringObject): Deleted.

  • runtime/StringPrototype.cpp:

(JSC::replaceUsingRegExpSearch):
(JSC::replace):
(JSC::stringProtoFuncReplaceUsingRegExp):
(JSC::stringProtoFuncToString):

  • runtime/SymbolPrototype.cpp:

(JSC::symbolProtoFuncToString):
(JSC::symbolProtoFuncValueOf):

  • tools/JSDollarVM.cpp:

(WTF::customGetValue):
(WTF::customSetValue):

  • wasm/js/JSWebAssemblyHelpers.h:

(JSC::isWebAssemblyHostFunction):

  • wasm/js/WebAssemblyWrapperFunction.cpp:

(JSC::WebAssemblyWrapperFunction::create):

Source/WebCore:

  • bindings/js/IDBBindingUtilities.cpp:

(WebCore::createIDBKeyFromValue):

  • bindings/js/JSDOMConvertDate.cpp:

(WebCore::valueToDate):

  • bindings/js/JSDOMGlobalObject.cpp:

(WebCore::JSDOMGlobalObject::scriptExecutionContext const):

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::toWrapped):

  • bindings/js/JSEventTargetCustom.cpp:
  • bindings/js/JSNodeCustom.cpp:

(WebCore::JSNode::pushEventHandlerScope const):

  • bindings/js/JSXPathNSResolverCustom.cpp:

(WebCore::JSXPathNSResolver::toWrapped):

  • bindings/js/ScriptState.cpp:

(WebCore::domWindowFromExecState):
(WebCore::scriptExecutionContextFromExecState):

  • bindings/js/SerializedScriptValue.cpp:

(WebCore::CloneSerializer::isArray):
(WebCore::CloneSerializer::isMap):
(WebCore::CloneSerializer::isSet):
(WebCore::CloneSerializer::dumpArrayBufferView):
(WebCore::CloneSerializer::dumpDOMPoint):
(WebCore::CloneSerializer::dumpDOMRect):
(WebCore::CloneSerializer::dumpDOMMatrix):
(WebCore::CloneSerializer::dumpIfTerminal):
(WebCore::CloneDeserializer::CloneDeserializer):
(WebCore::CloneDeserializer::readArrayBufferView):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateOverloadDispatcher):

  • bindings/scripts/test/JS/JSTestObj.cpp:

(WebCore::jsTestObjPrototypeFunctionOverloadedMethodOverloadDispatcher):
(WebCore::jsTestObjPrototypeFunctionOverloadedMethodWithOptionalParameterOverloadDispatcher):
(WebCore::jsTestObjPrototypeFunctionOverloadedMethodWithDistinguishingUnionOverloadDispatcher):
(WebCore::jsTestObjPrototypeFunctionOverloadedMethodWith2DistinguishingUnionsOverloadDispatcher):
(WebCore::jsTestObjPrototypeFunctionOverloadedMethodWithNonDistinguishingUnionOverloadDispatcher):
(WebCore::jsTestObjPrototypeFunctionOverloadWithNullableUnionOverloadDispatcher):
(WebCore::jsTestObjPrototypeFunctionOverloadWithNullableNonDistinguishingParameterOverloadDispatcher):
(WebCore::jsTestObjPrototypeFunctionTestPromiseOverloadedFunctionOverloadDispatcher):

  • bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp:

(WebCore::JSTestOverloadedConstructorsConstructor::construct):

  • bridge/c/c_instance.cpp:

(JSC::Bindings::CInstance::invokeMethod):

  • bridge/objc/WebScriptObject.mm:

(+[WebScriptObject _convertValueToObjcValue:originRootObject:rootObject:]):

  • bridge/objc/objc_instance.mm:

(ObjcInstance::invokeMethod):

  • bridge/objc/objc_runtime.mm:

(JSC::Bindings::callObjCFallbackObject):

  • bridge/runtime_method.cpp:

(JSC::callRuntimeMethod):

  • bridge/runtime_object.cpp:

(JSC::Bindings::callRuntimeObject):
(JSC::Bindings::callRuntimeConstructor):

  • inspector/WebInjectedScriptHost.cpp:

(WebCore::WebInjectedScriptHost::subtype):
(WebCore::WebInjectedScriptHost::isHTMLAllCollection):

Source/WebKit:

  • WebProcess/Plugins/Netscape/JSNPMethod.cpp:

(WebKit::callMethod):

  • WebProcess/Plugins/Netscape/JSNPObject.cpp:

(WebKit::callNPJSObject):
(WebKit::constructWithConstructor):

  • WebProcess/Plugins/Netscape/NPJSObject.cpp:

(WebKit::NPJSObject::create):

  • WebProcess/WebPage/WebFrame.cpp:

(WebKit::WebFrame::counterValue):

Source/WebKitLegacy/mac:

  • DOM/DOM.mm:

(+[DOMNode _nodeFromJSWrapper:]):

  • Plugins/Hosted/NetscapePluginInstanceProxy.mm:

(WebKit::NetscapePluginInstanceProxy::retainLocalObject):
(WebKit::NetscapePluginInstanceProxy::releaseLocalObject):

  • Plugins/Hosted/ProxyInstance.mm:

(WebKit::ProxyInstance::invokeMethod):

  • WebView/WebView.mm:

(aeDescFromJSValue):

Source/WebKitLegacy/win:

  • WebFrame.cpp:

(WebFrame::stringByEvaluatingJavaScriptInScriptWorld):

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