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

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

WebAssembly: JSWebAssemblyCallee should not be a JSCell
https://bugs.webkit.org/show_bug.cgi?id=170135

Reviewed by Michael Saboff.

Source/JavaScriptCore:

This patch is perhaps the last big change to the design of fundamental
Wasm API to allow for PIC. It changes JSWebAssemblyCallee into a thing
called Wasm::Callee. It serves the same purpose as before, except
Wasm::Callee is not a JSCell. I had to refactor the various parts of the
runtime that will see CallFrame's with Wasm::Callee's in the callee slot.
Thankfully, the parts of the runtime that Wasm touches are limited. The
main refactoring is changing the exception handling code, such as taking
a stack trace, to be friendly to seeing a non JSCell callee.

The callee() function on ExecState now returns a class I added in this
patch called CalleeBits. CalleeBits will tell you if the callee is a
JSCell or a Wasm::Callee. We tag Wasm::Callee's with a 1 in their lower
bit so we can easily tell what is and isn't a Wasm::Callee.

The stub that calls out from Wasm to JS still puts a JSCell callee
into the call frame, even though the callee logically represents a
Wasm frame. The reason for this is that we use the call IC infrastructure
to make a call out to JS code, and the code that writes the IC expects
a JSCell as the callee. This is knowingly part of our design. When we
do structured cloning of Wasm Modules, we'll need to regenerate these
JS call stubs.

  • API/JSContextRef.cpp:

(BacktraceFunctor::operator()):

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • debugger/Debugger.cpp:

(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::currentDebuggerCallFrame):

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::create):
(JSC::DebuggerCallFrame::DebuggerCallFrame):
(JSC::DebuggerCallFrame::currentPosition):
(JSC::DebuggerCallFrame::positionForCallFrame):

  • debugger/DebuggerCallFrame.h:
  • interpreter/CallFrame.cpp:

(JSC::CallFrame::vmEntryGlobalObject):
(JSC::CallFrame::wasmAwareLexicalGlobalObject):
(JSC::CallFrame::isAnyWasmCallee):
(JSC::CallFrame::callerSourceOrigin):

  • interpreter/CallFrame.h:

(JSC::ExecState::calleeAsValue):
(JSC::ExecState::jsCallee):
(JSC::ExecState::callee):
(JSC::ExecState::unsafeCallee):
(JSC::ExecState::scope):
(JSC::ExecState::iterate):

  • interpreter/CalleeBits.h: Added.

(JSC::CalleeBits::CalleeBits):
(JSC::CalleeBits::operator=):
(JSC::CalleeBits::boxWasm):
(JSC::CalleeBits::isWasm):
(JSC::CalleeBits::isCell):
(JSC::CalleeBits::asCell):
(JSC::CalleeBits::asWasmCallee):
(JSC::CalleeBits::rawPtr):

  • interpreter/Interpreter.cpp:

(JSC::GetStackTraceFunctor::operator()):
(JSC::Interpreter::getStackTrace):
(JSC::notifyDebuggerOfUnwinding):
(JSC::UnwindFunctor::UnwindFunctor):
(JSC::UnwindFunctor::operator()):
(JSC::UnwindFunctor::copyCalleeSavesToVMEntryFrameCalleeSavesBuffer):
(JSC::Interpreter::unwind):
(JSC::Interpreter::notifyDebuggerOfExceptionToBeThrown):

  • interpreter/Interpreter.h:
  • interpreter/Register.h:

(JSC::Register::pointer):

  • interpreter/ShadowChicken.cpp:

(JSC::ShadowChicken::update):

  • interpreter/ShadowChickenInlines.h:

(JSC::ShadowChicken::iterate):

  • interpreter/StackVisitor.cpp:

(JSC::StackVisitor::StackVisitor):
(JSC::StackVisitor::readFrame):
(JSC::StackVisitor::readNonInlinedFrame):
(JSC::StackVisitor::readInlinedFrame):
(JSC::StackVisitor::Frame::calleeSaveRegisters):
(JSC::StackVisitor::Frame::functionName):
(JSC::StackVisitor::Frame::dump):

  • interpreter/StackVisitor.h:

(JSC::StackVisitor::Frame::callee):
(JSC::StackVisitor::visit):

  • jit/Repatch.cpp:

(JSC::linkFor):
(JSC::linkPolymorphicCall):

  • jsc.cpp:

(callWasmFunction):
(functionTestWasmModuleFunctions):

  • runtime/ArrayPrototype.cpp:
  • runtime/Error.cpp:

(JSC::addErrorInfoAndGetBytecodeOffset):

  • runtime/ErrorInstance.cpp:

(JSC::ErrorInstance::finishCreation):

  • runtime/JSCell.cpp:

(JSC::JSCell::isAnyWasmCallee): Deleted.

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

(JSC::ExecState::vm):

  • runtime/JSFunction.cpp:

(JSC::RetrieveArgumentsFunctor::operator()):
(JSC::RetrieveCallerFunctionFunctor::operator()):

  • runtime/JSGlobalObject.cpp:
  • runtime/SamplingProfiler.cpp:

(JSC::FrameWalker::recordJSFrame):
(JSC::SamplingProfiler::processUnverifiedStackTraces):

  • runtime/SamplingProfiler.h:

(JSC::SamplingProfiler::UnprocessedStackFrame::UnprocessedStackFrame):

  • runtime/StackFrame.cpp:

(JSC::StackFrame::sourceURL):
(JSC::StackFrame::functionName):

  • runtime/StackFrame.h:

(JSC::StackFrame::wasm):

  • runtime/VM.cpp:

(JSC::VM::VM):
(JSC::VM::throwException):

  • runtime/VM.h:
  • wasm/JSWebAssembly.h:
  • wasm/WasmB3IRGenerator.cpp:
  • wasm/WasmBinding.cpp:

(JSC::Wasm::wasmToWasm):

  • wasm/WasmCallee.cpp: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.cpp.

(JSC::Wasm::Callee::Callee):
(JSC::JSWebAssemblyCallee::JSWebAssemblyCallee): Deleted.
(JSC::JSWebAssemblyCallee::finishCreation): Deleted.
(JSC::JSWebAssemblyCallee::destroy): Deleted.

  • wasm/WasmCallee.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.h.

(JSC::Wasm::Callee::create):
(JSC::JSWebAssemblyCallee::create): Deleted.
(JSC::JSWebAssemblyCallee::createStructure): Deleted.
(JSC::JSWebAssemblyCallee::entrypoint): Deleted.
(JSC::JSWebAssemblyCallee::calleeSaveRegisters): Deleted.

  • wasm/WasmContext.h:
  • wasm/WasmPlan.cpp:
  • wasm/WasmPlan.h:
  • wasm/WasmPlanInlines.h:

(JSC::Wasm::Plan::initializeCallees):

  • wasm/WasmThunks.cpp:

(JSC::Wasm::throwExceptionFromWasmThunkGenerator):

  • wasm/js/JSWebAssemblyCallee.cpp: Removed.
  • wasm/js/JSWebAssemblyCallee.h: Removed.
  • wasm/js/JSWebAssemblyCodeBlock.cpp:

(JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
(JSC::JSWebAssemblyCodeBlock::initialize):
(JSC::JSWebAssemblyCodeBlock::visitChildren):

  • wasm/js/JSWebAssemblyCodeBlock.h:

(JSC::JSWebAssemblyCodeBlock::create):
(JSC::JSWebAssemblyCodeBlock::jsEntrypointCalleeFromFunctionIndexSpace):
(JSC::JSWebAssemblyCodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace):
(JSC::JSWebAssemblyCodeBlock::wasmToJsCallStubForImport):
(JSC::JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub):
(JSC::JSWebAssemblyCodeBlock::setJSEntrypointCallee):
(JSC::JSWebAssemblyCodeBlock::setWasmEntrypointCallee):
(JSC::JSWebAssemblyCodeBlock::offsetOfImportStubs):
(JSC::JSWebAssemblyCodeBlock::allocationSize):
(JSC::JSWebAssemblyCodeBlock::importWasmToJSStub):
(JSC::JSWebAssemblyCodeBlock::callees): Deleted.
(JSC::JSWebAssemblyCodeBlock::offsetOfCallees): Deleted.

  • wasm/js/JSWebAssemblyInstance.h:

(JSC::JSWebAssemblyInstance::webAssemblyToJSCallee):

  • wasm/js/JSWebAssemblyModule.cpp:
  • wasm/js/WebAssemblyFunction.cpp:

(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::create):
(JSC::WebAssemblyFunction::WebAssemblyFunction):
(JSC::WebAssemblyFunction::visitChildren):
(JSC::WebAssemblyFunction::finishCreation):

  • wasm/js/WebAssemblyFunction.h:

(JSC::WebAssemblyFunction::wasmEntrypoint):
(JSC::WebAssemblyFunction::jsEntrypoint):
(JSC::WebAssemblyFunction::offsetOfWasmEntrypoint):
(JSC::WebAssemblyFunction::offsetOfWasmEntryPointCode): Deleted.

  • wasm/js/WebAssemblyModuleConstructor.cpp:
  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):

Source/WebCore:

  • bindings/js/JSDOMWindowBase.cpp:

(WebCore::callerDOMWindow):

  • Property svn:eol-style set to native
File size: 143.7 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 "BuiltinExecutableCreator.h"
28#include "BuiltinNames.h"
29#include "ButterflyInlines.h"
30#include "CodeBlock.h"
31#include "Completion.h"
32#include "ConfigFile.h"
33#include "DOMJITGetterSetter.h"
34#include "DOMJITPatchpoint.h"
35#include "DOMJITPatchpointParams.h"
36#include "Disassembler.h"
37#include "Exception.h"
38#include "ExceptionHelpers.h"
39#include "GetterSetter.h"
40#include "HeapProfiler.h"
41#include "HeapSnapshotBuilder.h"
42#include "InitializeThreading.h"
43#include "Interpreter.h"
44#include "JIT.h"
45#include "JSArray.h"
46#include "JSArrayBuffer.h"
47#include "JSCInlines.h"
48#include "JSFunction.h"
49#include "JSInternalPromise.h"
50#include "JSInternalPromiseDeferred.h"
51#include "JSLock.h"
52#include "JSModuleLoader.h"
53#include "JSNativeStdFunction.h"
54#include "JSONObject.h"
55#include "JSProxy.h"
56#include "JSSourceCode.h"
57#include "JSString.h"
58#include "JSTypedArrays.h"
59#include "JSWebAssemblyInstance.h"
60#include "JSWebAssemblyMemory.h"
61#include "LLIntData.h"
62#include "LLIntThunks.h"
63#include "ObjectConstructor.h"
64#include "ParserError.h"
65#include "ProfilerDatabase.h"
66#include "PromiseDeferredTimer.h"
67#include "ProtoCallFrame.h"
68#include "ReleaseHeapAccessScope.h"
69#include "SamplingProfiler.h"
70#include "ShadowChicken.h"
71#include "StackVisitor.h"
72#include "StructureInlines.h"
73#include "StructureRareDataInlines.h"
74#include "SuperSampler.h"
75#include "TestRunnerUtils.h"
76#include "TypeProfilerLog.h"
77#include "WasmCallee.h"
78#include "WasmContext.h"
79#include "WasmFaultSignalHandler.h"
80#include "WasmMemory.h"
81#include "WasmPlanInlines.h"
82#include "WasmWorklist.h"
83#include <locale.h>
84#include <math.h>
85#include <stdio.h>
86#include <stdlib.h>
87#include <string.h>
88#include <thread>
89#include <type_traits>
90#include <wtf/CommaPrinter.h>
91#include <wtf/CurrentTime.h>
92#include <wtf/MainThread.h>
93#include <wtf/NeverDestroyed.h>
94#include <wtf/StringPrintStream.h>
95#include <wtf/text/StringBuilder.h>
96
97#if OS(WINDOWS)
98#include <direct.h>
99#else
100#include <unistd.h>
101#endif
102
103#if HAVE(READLINE)
104// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
105// We #define it to something else to avoid this conflict.
106#define Function ReadlineFunction
107#include <readline/history.h>
108#include <readline/readline.h>
109#undef Function
110#endif
111
112#if HAVE(SYS_TIME_H)
113#include <sys/time.h>
114#endif
115
116#if HAVE(SIGNAL_H)
117#include <signal.h>
118#endif
119
120#if COMPILER(MSVC)
121#include <crtdbg.h>
122#include <mmsystem.h>
123#include <windows.h>
124#endif
125
126#if PLATFORM(IOS) && CPU(ARM_THUMB2)
127#include <fenv.h>
128#include <arm/arch.h>
129#endif
130
131#if !defined(PATH_MAX)
132#define PATH_MAX 4096
133#endif
134
135using namespace JSC;
136using namespace WTF;
137
138namespace {
139
140NO_RETURN_WITH_VALUE static void jscExit(int status)
141{
142 waitForAsynchronousDisassembly();
143
144#if ENABLE(DFG_JIT)
145 if (DFG::isCrashing()) {
146 for (;;) {
147#if OS(WINDOWS)
148 Sleep(1000);
149#else
150 pause();
151#endif
152 }
153 }
154#endif // ENABLE(DFG_JIT)
155 exit(status);
156}
157
158class Element;
159class ElementHandleOwner;
160class Masuqerader;
161class Root;
162class RuntimeArray;
163
164class Element : public JSNonFinalObject {
165public:
166 Element(VM& vm, Structure* structure)
167 : Base(vm, structure)
168 {
169 }
170
171 typedef JSNonFinalObject Base;
172
173 Root* root() const { return m_root.get(); }
174 void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); }
175
176 static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
177 {
178 Structure* structure = createStructure(vm, globalObject, jsNull());
179 Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure);
180 element->finishCreation(vm, root);
181 return element;
182 }
183
184 void finishCreation(VM&, Root*);
185
186 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
187 {
188 Element* thisObject = jsCast<Element*>(cell);
189 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
190 Base::visitChildren(thisObject, visitor);
191 visitor.append(thisObject->m_root);
192 }
193
194 static ElementHandleOwner* handleOwner();
195
196 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
197 {
198 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
199 }
200
201 DECLARE_INFO;
202
203private:
204 WriteBarrier<Root> m_root;
205};
206
207class ElementHandleOwner : public WeakHandleOwner {
208public:
209 bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) override
210 {
211 Element* element = jsCast<Element*>(handle.slot()->asCell());
212 return visitor.containsOpaqueRoot(element->root());
213 }
214};
215
216class Masquerader : public JSNonFinalObject {
217public:
218 Masquerader(VM& vm, Structure* structure)
219 : Base(vm, structure)
220 {
221 }
222
223 typedef JSNonFinalObject Base;
224 static const unsigned StructureFlags = Base::StructureFlags | JSC::MasqueradesAsUndefined;
225
226 static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
227 {
228 globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(vm, "Masquerading object allocated");
229 Structure* structure = createStructure(vm, globalObject, jsNull());
230 Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
231 result->finishCreation(vm);
232 return result;
233 }
234
235 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
236 {
237 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
238 }
239
240 DECLARE_INFO;
241};
242
243class Root : public JSDestructibleObject {
244public:
245 Root(VM& vm, Structure* structure)
246 : Base(vm, structure)
247 {
248 }
249
250 Element* element()
251 {
252 return m_element.get();
253 }
254
255 void setElement(Element* element)
256 {
257 Weak<Element> newElement(element, Element::handleOwner());
258 m_element.swap(newElement);
259 }
260
261 static Root* create(VM& vm, JSGlobalObject* globalObject)
262 {
263 Structure* structure = createStructure(vm, globalObject, jsNull());
264 Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
265 root->finishCreation(vm);
266 return root;
267 }
268
269 typedef JSDestructibleObject Base;
270
271 DECLARE_INFO;
272
273 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
274 {
275 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
276 }
277
278 static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
279 {
280 Base::visitChildren(thisObject, visitor);
281 visitor.addOpaqueRoot(thisObject);
282 }
283
284private:
285 Weak<Element> m_element;
286};
287
288class ImpureGetter : public JSNonFinalObject {
289public:
290 ImpureGetter(VM& vm, Structure* structure)
291 : Base(vm, structure)
292 {
293 }
294
295 DECLARE_INFO;
296 typedef JSNonFinalObject Base;
297 static const unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::OverridesGetOwnPropertySlot;
298
299 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
300 {
301 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
302 }
303
304 static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
305 {
306 ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
307 getter->finishCreation(vm, delegate);
308 return getter;
309 }
310
311 void finishCreation(VM& vm, JSObject* delegate)
312 {
313 Base::finishCreation(vm);
314 if (delegate)
315 m_delegate.set(vm, this, delegate);
316 }
317
318 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
319 {
320 VM& vm = exec->vm();
321 auto scope = DECLARE_THROW_SCOPE(vm);
322 ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
323
324 if (thisObject->m_delegate) {
325 if (thisObject->m_delegate->getPropertySlot(exec, name, slot))
326 return true;
327 RETURN_IF_EXCEPTION(scope, false);
328 }
329
330 return Base::getOwnPropertySlot(object, exec, name, slot);
331 }
332
333 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
334 {
335 Base::visitChildren(cell, visitor);
336 ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell);
337 visitor.append(thisObject->m_delegate);
338 }
339
340 void setDelegate(VM& vm, JSObject* delegate)
341 {
342 m_delegate.set(vm, this, delegate);
343 }
344
345private:
346 WriteBarrier<JSObject> m_delegate;
347};
348
349class CustomGetter : public JSNonFinalObject {
350public:
351 CustomGetter(VM& vm, Structure* structure)
352 : Base(vm, structure)
353 {
354 }
355
356 DECLARE_INFO;
357 typedef JSNonFinalObject Base;
358 static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot;
359
360 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
361 {
362 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
363 }
364
365 static CustomGetter* create(VM& vm, Structure* structure)
366 {
367 CustomGetter* getter = new (NotNull, allocateCell<CustomGetter>(vm.heap, sizeof(CustomGetter))) CustomGetter(vm, structure);
368 getter->finishCreation(vm);
369 return getter;
370 }
371
372 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
373 {
374 CustomGetter* thisObject = jsCast<CustomGetter*>(object);
375 if (propertyName == PropertyName(Identifier::fromString(exec, "customGetter"))) {
376 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->customGetter);
377 return true;
378 }
379
380 if (propertyName == PropertyName(Identifier::fromString(exec, "customGetterAccessor"))) {
381 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum | CustomAccessor, thisObject->customGetterAcessor);
382 return true;
383 }
384
385 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
386 }
387
388private:
389 static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
390 {
391 VM& vm = exec->vm();
392 auto scope = DECLARE_THROW_SCOPE(vm);
393
394 CustomGetter* thisObject = jsDynamicCast<CustomGetter*>(vm, JSValue::decode(thisValue));
395 if (!thisObject)
396 return throwVMTypeError(exec, scope);
397 bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow"))).toBoolean(exec);
398 RETURN_IF_EXCEPTION(scope, encodedJSValue());
399 if (shouldThrow)
400 return throwVMTypeError(exec, scope);
401 return JSValue::encode(jsNumber(100));
402 }
403
404 static EncodedJSValue customGetterAcessor(ExecState* exec, EncodedJSValue thisValue, PropertyName)
405 {
406 VM& vm = exec->vm();
407 auto scope = DECLARE_THROW_SCOPE(vm);
408
409 JSObject* thisObject = jsDynamicCast<JSObject*>(vm, JSValue::decode(thisValue));
410 if (!thisObject)
411 return throwVMTypeError(exec, scope);
412 bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow"))).toBoolean(exec);
413 if (shouldThrow)
414 return throwVMTypeError(exec, scope);
415 return JSValue::encode(jsNumber(100));
416 }
417};
418
419class RuntimeArray : public JSArray {
420public:
421 typedef JSArray Base;
422 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
423
424 static RuntimeArray* create(ExecState* exec)
425 {
426 VM& vm = exec->vm();
427 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
428 Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
429 RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
430 runtimeArray->finishCreation(exec);
431 vm.heap.addFinalizer(runtimeArray, destroy);
432 return runtimeArray;
433 }
434
435 ~RuntimeArray() { }
436
437 static void destroy(JSCell* cell)
438 {
439 static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
440 }
441
442 static const bool needsDestruction = false;
443
444 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
445 {
446 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
447 if (propertyName == exec->propertyNames().length) {
448 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
449 return true;
450 }
451
452 std::optional<uint32_t> index = parseIndex(propertyName);
453 if (index && index.value() < thisObject->getLength()) {
454 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
455 return true;
456 }
457
458 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
459 }
460
461 static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
462 {
463 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
464 if (index < thisObject->getLength()) {
465 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
466 return true;
467 }
468
469 return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
470 }
471
472 static NO_RETURN_DUE_TO_CRASH bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
473 {
474 RELEASE_ASSERT_NOT_REACHED();
475 }
476
477 static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
478 {
479 RELEASE_ASSERT_NOT_REACHED();
480 }
481
482 unsigned getLength() const { return m_vector.size(); }
483
484 DECLARE_INFO;
485
486 static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
487 {
488 return globalObject->arrayPrototype();
489 }
490
491 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
492 {
493 return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass);
494 }
495
496protected:
497 void finishCreation(ExecState* exec)
498 {
499 VM& vm = exec->vm();
500 Base::finishCreation(vm);
501 ASSERT(inherits(vm, info()));
502
503 for (size_t i = 0; i < exec->argumentCount(); i++)
504 m_vector.append(exec->argument(i).toInt32(exec));
505 }
506
507private:
508 RuntimeArray(ExecState* exec, Structure* structure)
509 : JSArray(exec->vm(), structure, 0)
510 {
511 }
512
513 static EncodedJSValue lengthGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
514 {
515 VM& vm = exec->vm();
516 auto scope = DECLARE_THROW_SCOPE(vm);
517
518 RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(vm, JSValue::decode(thisValue));
519 if (!thisObject)
520 return throwVMTypeError(exec, scope);
521 return JSValue::encode(jsNumber(thisObject->getLength()));
522 }
523
524 Vector<int> m_vector;
525};
526
527class SimpleObject : public JSNonFinalObject {
528public:
529 SimpleObject(VM& vm, Structure* structure)
530 : Base(vm, structure)
531 {
532 }
533
534 typedef JSNonFinalObject Base;
535 static const bool needsDestruction = false;
536
537 static SimpleObject* create(VM& vm, JSGlobalObject* globalObject)
538 {
539 Structure* structure = createStructure(vm, globalObject, jsNull());
540 SimpleObject* simpleObject = new (NotNull, allocateCell<SimpleObject>(vm.heap, sizeof(SimpleObject))) SimpleObject(vm, structure);
541 simpleObject->finishCreation(vm);
542 return simpleObject;
543 }
544
545 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
546 {
547 SimpleObject* thisObject = jsCast<SimpleObject*>(cell);
548 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
549 Base::visitChildren(thisObject, visitor);
550 visitor.append(thisObject->m_hiddenValue);
551 }
552
553 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
554 {
555 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
556 }
557
558 JSValue hiddenValue()
559 {
560 return m_hiddenValue.get();
561 }
562
563 void setHiddenValue(VM& vm, JSValue value)
564 {
565 ASSERT(value.isCell());
566 m_hiddenValue.set(vm, this, value);
567 }
568
569 DECLARE_INFO;
570
571private:
572 WriteBarrier<JSC::Unknown> m_hiddenValue;
573};
574
575class DOMJITNode : public JSNonFinalObject {
576public:
577 DOMJITNode(VM& vm, Structure* structure)
578 : Base(vm, structure)
579 {
580 }
581
582 DECLARE_INFO;
583 typedef JSNonFinalObject Base;
584 static const unsigned StructureFlags = Base::StructureFlags;
585
586 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
587 {
588 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
589 }
590
591#if ENABLE(JIT)
592 static Ref<DOMJIT::Patchpoint> checkDOMJITNode()
593 {
594 Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
595 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
596 CCallHelpers::JumpList failureCases;
597 failureCases.append(jit.branch8(
598 CCallHelpers::NotEqual,
599 CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
600 CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
601 return failureCases;
602 });
603 return patchpoint;
604 }
605#endif
606
607 static DOMJITNode* create(VM& vm, Structure* structure)
608 {
609 DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure);
610 getter->finishCreation(vm);
611 return getter;
612 }
613
614 int32_t value() const
615 {
616 return m_value;
617 }
618
619 static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(DOMJITNode, m_value); }
620
621private:
622 int32_t m_value { 42 };
623};
624
625class DOMJITGetter : public DOMJITNode {
626public:
627 DOMJITGetter(VM& vm, Structure* structure)
628 : Base(vm, structure)
629 {
630 }
631
632 DECLARE_INFO;
633 typedef DOMJITNode Base;
634 static const unsigned StructureFlags = Base::StructureFlags;
635
636 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
637 {
638 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
639 }
640
641 static DOMJITGetter* create(VM& vm, Structure* structure)
642 {
643 DOMJITGetter* getter = new (NotNull, allocateCell<DOMJITGetter>(vm.heap, sizeof(DOMJITGetter))) DOMJITGetter(vm, structure);
644 getter->finishCreation(vm);
645 return getter;
646 }
647
648 class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
649 public:
650 DOMJITNodeDOMJIT()
651 : DOMJIT::GetterSetter(DOMJITGetter::customGetter, nullptr, DOMJITNode::info(), SpecInt32Only)
652 {
653 }
654
655#if ENABLE(JIT)
656 Ref<DOMJIT::Patchpoint> checkDOM() override
657 {
658 return DOMJITNode::checkDOMJITNode();
659 }
660
661 static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer)
662 {
663 NativeCallFrameTracer tracer(&exec->vm(), exec);
664 return JSValue::encode(jsNumber(static_cast<DOMJITGetter*>(pointer)->value()));
665 }
666
667 Ref<DOMJIT::CallDOMGetterPatchpoint> callDOMGetter() override
668 {
669 Ref<DOMJIT::CallDOMGetterPatchpoint> patchpoint = DOMJIT::CallDOMGetterPatchpoint::create();
670 patchpoint->requireGlobalObject = false;
671 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
672 JSValueRegs results = params[0].jsValueRegs();
673 GPRReg dom = params[1].gpr();
674 params.addSlowPathCall(jit.jump(), jit, slowCall, results, dom);
675 return CCallHelpers::JumpList();
676
677 });
678 return patchpoint;
679 }
680#endif
681 };
682
683 static DOMJIT::GetterSetter* domJITNodeGetterSetter()
684 {
685 static NeverDestroyed<DOMJITNodeDOMJIT> graph;
686 return &graph.get();
687 }
688
689private:
690 void finishCreation(VM& vm)
691 {
692 Base::finishCreation(vm);
693 DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
694 CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
695 putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
696 }
697
698 static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
699 {
700 VM& vm = exec->vm();
701 auto scope = DECLARE_THROW_SCOPE(vm);
702
703 DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(vm, JSValue::decode(thisValue));
704 if (!thisObject)
705 return throwVMTypeError(exec, scope);
706 return JSValue::encode(jsNumber(thisObject->value()));
707 }
708};
709
710class DOMJITGetterComplex : public DOMJITNode {
711public:
712 DOMJITGetterComplex(VM& vm, Structure* structure)
713 : Base(vm, structure)
714 {
715 }
716
717 DECLARE_INFO;
718 typedef DOMJITNode Base;
719 static const unsigned StructureFlags = Base::StructureFlags;
720
721 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
722 {
723 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
724 }
725
726 static DOMJITGetterComplex* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
727 {
728 DOMJITGetterComplex* getter = new (NotNull, allocateCell<DOMJITGetterComplex>(vm.heap, sizeof(DOMJITGetterComplex))) DOMJITGetterComplex(vm, structure);
729 getter->finishCreation(vm, globalObject);
730 return getter;
731 }
732
733 class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
734 public:
735 DOMJITNodeDOMJIT()
736 : DOMJIT::GetterSetter(DOMJITGetterComplex::customGetter, nullptr, DOMJITNode::info(), SpecInt32Only)
737 {
738 }
739
740#if ENABLE(JIT)
741 Ref<DOMJIT::Patchpoint> checkDOM() override
742 {
743 return DOMJITNode::checkDOMJITNode();
744 }
745
746 static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer)
747 {
748 VM& vm = exec->vm();
749 NativeCallFrameTracer tracer(&vm, exec);
750 auto scope = DECLARE_THROW_SCOPE(vm);
751 auto* object = static_cast<DOMJITNode*>(pointer);
752 auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(vm, object);
753 if (domjitGetterComplex) {
754 if (domjitGetterComplex->m_enableException)
755 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
756 }
757 return JSValue::encode(jsNumber(object->value()));
758 }
759
760 Ref<DOMJIT::CallDOMGetterPatchpoint> callDOMGetter() override
761 {
762 RefPtr<DOMJIT::CallDOMGetterPatchpoint> patchpoint = DOMJIT::CallDOMGetterPatchpoint::create();
763 static_assert(GPRInfo::numberOfRegisters >= 4, "Number of registers should be larger or equal to 4.");
764 patchpoint->numGPScratchRegisters = GPRInfo::numberOfRegisters - 4;
765 patchpoint->numFPScratchRegisters = 3;
766 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
767 JSValueRegs results = params[0].jsValueRegs();
768 GPRReg domGPR = params[1].gpr();
769 for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i)
770 jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i));
771
772 params.addSlowPathCall(jit.jump(), jit, slowCall, results, domGPR);
773 return CCallHelpers::JumpList();
774
775 });
776 return *patchpoint.get();
777 }
778#endif
779 };
780
781 static DOMJIT::GetterSetter* domJITNodeGetterSetter()
782 {
783 static NeverDestroyed<DOMJITNodeDOMJIT> graph;
784 return &graph.get();
785 }
786
787private:
788 void finishCreation(VM& vm, JSGlobalObject* globalObject)
789 {
790 Base::finishCreation(vm);
791 DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
792 CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
793 putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
794 putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "enableException"), 0, functionEnableException, NoIntrinsic, 0);
795 }
796
797 static EncodedJSValue JSC_HOST_CALL functionEnableException(ExecState* exec)
798 {
799 VM& vm = exec->vm();
800 auto* object = jsDynamicCast<DOMJITGetterComplex*>(vm, exec->thisValue());
801 if (object)
802 object->m_enableException = true;
803 return JSValue::encode(jsUndefined());
804 }
805
806 static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
807 {
808 VM& vm = exec->vm();
809 auto scope = DECLARE_THROW_SCOPE(vm);
810
811 auto* thisObject = jsDynamicCast<DOMJITNode*>(vm, JSValue::decode(thisValue));
812 if (!thisObject)
813 return throwVMTypeError(exec, scope);
814 if (auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(vm, JSValue::decode(thisValue))) {
815 if (domjitGetterComplex->m_enableException)
816 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
817 }
818 return JSValue::encode(jsNumber(thisObject->value()));
819 }
820
821 bool m_enableException { false };
822};
823
824class DOMJITFunctionObject : public DOMJITNode {
825public:
826 DOMJITFunctionObject(VM& vm, Structure* structure)
827 : Base(vm, structure)
828 {
829 }
830
831 DECLARE_INFO;
832 typedef DOMJITNode Base;
833 static const unsigned StructureFlags = Base::StructureFlags;
834
835
836 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
837 {
838 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
839 }
840
841 static DOMJITFunctionObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
842 {
843 DOMJITFunctionObject* object = new (NotNull, allocateCell<DOMJITFunctionObject>(vm.heap, sizeof(DOMJITFunctionObject))) DOMJITFunctionObject(vm, structure);
844 object->finishCreation(vm, globalObject);
845 return object;
846 }
847
848 static EncodedJSValue JSC_HOST_CALL safeFunction(ExecState* exec)
849 {
850 VM& vm = exec->vm();
851 auto scope = DECLARE_THROW_SCOPE(vm);
852
853 DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(vm, exec->thisValue());
854 if (!thisObject)
855 return throwVMTypeError(exec, scope);
856 return JSValue::encode(jsNumber(thisObject->value()));
857 }
858
859#if ENABLE(JIT)
860 static EncodedJSValue JIT_OPERATION unsafeFunction(ExecState* exec, DOMJITNode* node)
861 {
862 NativeCallFrameTracer tracer(&exec->vm(), exec);
863 return JSValue::encode(jsNumber(node->value()));
864 }
865
866 static Ref<DOMJIT::Patchpoint> checkDOMJITNode()
867 {
868 static const double value = 42.0;
869 Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
870 patchpoint->numFPScratchRegisters = 1;
871 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
872 CCallHelpers::JumpList failureCases;
873 // May use scratch registers.
874 jit.loadDouble(CCallHelpers::TrustedImmPtr(&value), params.fpScratch(0));
875 failureCases.append(jit.branch8(
876 CCallHelpers::NotEqual,
877 CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
878 CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
879 return failureCases;
880 });
881 return patchpoint;
882 }
883#endif
884
885private:
886 void finishCreation(VM&, JSGlobalObject*);
887};
888
889#if ENABLE(JIT)
890static const DOMJIT::Signature DOMJITFunctionObjectSignature((uintptr_t)DOMJITFunctionObject::unsafeFunction, DOMJITFunctionObject::checkDOMJITNode, DOMJITFunctionObject::info(), DOMJIT::Effect::forRead(DOMJIT::HeapRange::top()), SpecInt32Only);
891#endif
892
893void DOMJITFunctionObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
894{
895 Base::finishCreation(vm);
896#if ENABLE(JIT)
897 putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "func"), 0, safeFunction, NoIntrinsic, &DOMJITFunctionObjectSignature, ReadOnly);
898#else
899 putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "func"), 0, safeFunction, NoIntrinsic, nullptr, ReadOnly);
900#endif
901}
902
903
904const ClassInfo Element::s_info = { "Element", &Base::s_info, nullptr, CREATE_METHOD_TABLE(Element) };
905const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, nullptr, CREATE_METHOD_TABLE(Masquerader) };
906const ClassInfo Root::s_info = { "Root", &Base::s_info, nullptr, CREATE_METHOD_TABLE(Root) };
907const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, nullptr, CREATE_METHOD_TABLE(ImpureGetter) };
908const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, nullptr, CREATE_METHOD_TABLE(CustomGetter) };
909const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITNode) };
910const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITGetter) };
911const ClassInfo DOMJITGetterComplex::s_info = { "DOMJITGetterComplex", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITGetterComplex) };
912const ClassInfo DOMJITFunctionObject::s_info = { "DOMJITFunctionObject", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITFunctionObject) };
913const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RuntimeArray) };
914const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, nullptr, CREATE_METHOD_TABLE(SimpleObject) };
915static unsigned asyncTestPasses { 0 };
916static unsigned asyncTestExpectedPasses { 0 };
917
918ElementHandleOwner* Element::handleOwner()
919{
920 static ElementHandleOwner* owner = 0;
921 if (!owner)
922 owner = new ElementHandleOwner();
923 return owner;
924}
925
926void Element::finishCreation(VM& vm, Root* root)
927{
928 Base::finishCreation(vm);
929 setRoot(vm, root);
930 m_root->setElement(this);
931}
932
933}
934
935static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
936
937class CommandLine;
938class GlobalObject;
939class Workers;
940
941template<typename Func>
942int runJSC(CommandLine, const Func&);
943static void checkException(GlobalObject*, bool isLastFile, bool hasException, JSValue, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool& success);
944
945class Message : public ThreadSafeRefCounted<Message> {
946public:
947 Message(ArrayBufferContents&&, int32_t);
948 ~Message();
949
950 ArrayBufferContents&& releaseContents() { return WTFMove(m_contents); }
951 int32_t index() const { return m_index; }
952
953private:
954 ArrayBufferContents m_contents;
955 int32_t m_index { 0 };
956};
957
958class Worker : public BasicRawSentinelNode<Worker> {
959public:
960 Worker(Workers&);
961 ~Worker();
962
963 void enqueue(const AbstractLocker&, RefPtr<Message>);
964 RefPtr<Message> dequeue();
965
966 static Worker& current();
967
968private:
969 static ThreadSpecific<Worker*>& currentWorker();
970
971 Workers& m_workers;
972 Deque<RefPtr<Message>> m_messages;
973};
974
975class Workers {
976public:
977 Workers();
978 ~Workers();
979
980 template<typename Func>
981 void broadcast(const Func&);
982
983 void report(String);
984 String tryGetReport();
985 String getReport();
986
987 static Workers& singleton();
988
989private:
990 friend class Worker;
991
992 Lock m_lock;
993 Condition m_condition;
994 SentinelLinkedList<Worker, BasicRawSentinelNode<Worker>> m_workers;
995 Deque<String> m_reports;
996};
997
998static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
999static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
1000static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
1001static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
1002static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
1003static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
1004static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState*);
1005static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState*);
1006static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
1007static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
1008static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
1009
1010static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
1011static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
1012static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
1013static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
1014static EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState*);
1015static EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState*);
1016static EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState*);
1017static EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState*);
1018static EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState*);
1019static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
1020static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
1021static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
1022static EncodedJSValue JSC_HOST_CALL functionSleepSeconds(ExecState*);
1023static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
1024static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
1025static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
1026static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
1027static EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*);
1028static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*);
1029static EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState*);
1030static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState*);
1031#ifndef NDEBUG
1032static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
1033#endif
1034static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
1035static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
1036static EncodedJSValue JSC_HOST_CALL functionRunString(ExecState*);
1037static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
1038static EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState*);
1039static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
1040static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
1041static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
1042static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
1043static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
1044static EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState*);
1045static EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState*);
1046static EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState*);
1047static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
1048static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
1049static EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState*);
1050static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
1051static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
1052static EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState*);
1053static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
1054static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*);
1055static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
1056static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
1057static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
1058static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
1059static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
1060static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
1061static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
1062static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
1063static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
1064static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
1065static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
1066static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
1067static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
1068static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
1069static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*);
1070static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*);
1071static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*);
1072static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*);
1073static EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState*);
1074static EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState*);
1075static EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*);
1076static EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState*);
1077static EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*);
1078static EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState*);
1079#if ENABLE(SAMPLING_PROFILER)
1080static EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState*);
1081static EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState*);
1082#endif
1083
1084static EncodedJSValue JSC_HOST_CALL functionMaxArguments(ExecState*);
1085static EncodedJSValue JSC_HOST_CALL functionAsyncTestStart(ExecState*);
1086static EncodedJSValue JSC_HOST_CALL functionAsyncTestPassed(ExecState*);
1087
1088#if ENABLE(WEBASSEMBLY)
1089static EncodedJSValue JSC_HOST_CALL functionTestWasmModuleFunctions(ExecState*);
1090static EncodedJSValue JSC_HOST_CALL functionWebAssemblyMemoryMode(ExecState*);
1091#endif
1092
1093#if ENABLE(SAMPLING_FLAGS)
1094static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
1095static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
1096#endif
1097
1098static EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState*);
1099static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState*);
1100static EncodedJSValue JSC_HOST_CALL functionGetRandomSeed(ExecState*);
1101static EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState*);
1102static EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState*);
1103static EncodedJSValue JSC_HOST_CALL functionCallerSourceOrigin(ExecState*);
1104static EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState*);
1105static EncodedJSValue JSC_HOST_CALL functionDollarCreateRealm(ExecState*);
1106static EncodedJSValue JSC_HOST_CALL functionDollarDetachArrayBuffer(ExecState*);
1107static EncodedJSValue JSC_HOST_CALL functionDollarEvalScript(ExecState*);
1108static EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState*);
1109static EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState*);
1110static EncodedJSValue JSC_HOST_CALL functionDollarAgentReport(ExecState*);
1111static EncodedJSValue JSC_HOST_CALL functionDollarAgentSleep(ExecState*);
1112static EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState*);
1113static EncodedJSValue JSC_HOST_CALL functionDollarAgentGetReport(ExecState*);
1114static EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*);
1115static EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState*);
1116static EncodedJSValue JSC_HOST_CALL functionHeapCapacity(ExecState*);
1117static EncodedJSValue JSC_HOST_CALL functionFlashHeapAccess(ExecState*);
1118
1119struct Script {
1120 enum class StrictMode {
1121 Strict,
1122 Sloppy
1123 };
1124
1125 enum class ScriptType {
1126 Script,
1127 Module
1128 };
1129
1130 enum class CodeSource {
1131 File,
1132 CommandLine
1133 };
1134
1135 StrictMode strictMode;
1136 CodeSource codeSource;
1137 ScriptType scriptType;
1138 char* argument;
1139
1140 Script(StrictMode strictMode, CodeSource codeSource, ScriptType scriptType, char *argument)
1141 : strictMode(strictMode)
1142 , codeSource(codeSource)
1143 , scriptType(scriptType)
1144 , argument(argument)
1145 {
1146 if (strictMode == StrictMode::Strict)
1147 ASSERT(codeSource == CodeSource::File);
1148 }
1149};
1150
1151class CommandLine {
1152public:
1153 CommandLine(int argc, char** argv)
1154 {
1155 parseArguments(argc, argv);
1156 }
1157
1158 bool m_interactive { false };
1159 bool m_dump { false };
1160 bool m_module { false };
1161 bool m_exitCode { false };
1162 Vector<Script> m_scripts;
1163 Vector<String> m_arguments;
1164 bool m_profile { false };
1165 String m_profilerOutput;
1166 String m_uncaughtExceptionName;
1167 bool m_alwaysDumpUncaughtException { false };
1168 bool m_dumpSamplingProfilerData { false };
1169 bool m_enableRemoteDebugging { false };
1170
1171 void parseArguments(int, char**);
1172};
1173
1174static const char interactivePrompt[] = ">>> ";
1175
1176class StopWatch {
1177public:
1178 void start();
1179 void stop();
1180 long getElapsedMS(); // call stop() first
1181
1182private:
1183 double m_startTime;
1184 double m_stopTime;
1185};
1186
1187void StopWatch::start()
1188{
1189 m_startTime = monotonicallyIncreasingTime();
1190}
1191
1192void StopWatch::stop()
1193{
1194 m_stopTime = monotonicallyIncreasingTime();
1195}
1196
1197long StopWatch::getElapsedMS()
1198{
1199 return static_cast<long>((m_stopTime - m_startTime) * 1000);
1200}
1201
1202template<typename Vector>
1203static inline String stringFromUTF(const Vector& utf8)
1204{
1205 return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size());
1206}
1207
1208template<typename Vector>
1209static inline SourceCode jscSource(const Vector& utf8, const SourceOrigin& sourceOrigin, const String& filename)
1210{
1211 String str = stringFromUTF(utf8);
1212 return makeSource(str, sourceOrigin, filename);
1213}
1214
1215class GlobalObject : public JSGlobalObject {
1216private:
1217 GlobalObject(VM&, Structure*);
1218
1219public:
1220 typedef JSGlobalObject Base;
1221
1222 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
1223 {
1224 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
1225 object->finishCreation(vm, arguments);
1226 return object;
1227 }
1228
1229 static const bool needsDestruction = false;
1230
1231 DECLARE_INFO;
1232 static const GlobalObjectMethodTable s_globalObjectMethodTable;
1233
1234 static Structure* createStructure(VM& vm, JSValue prototype)
1235 {
1236 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
1237 }
1238
1239 static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags::createAllEnabled(); }
1240
1241protected:
1242 void finishCreation(VM& vm, const Vector<String>& arguments)
1243 {
1244 Base::finishCreation(vm);
1245
1246 addFunction(vm, "debug", functionDebug, 1);
1247 addFunction(vm, "describe", functionDescribe, 1);
1248 addFunction(vm, "describeArray", functionDescribeArray, 1);
1249 addFunction(vm, "print", functionPrintStdOut, 1);
1250 addFunction(vm, "printErr", functionPrintStdErr, 1);
1251 addFunction(vm, "quit", functionQuit, 0);
1252 addFunction(vm, "abort", functionAbort, 0);
1253 addFunction(vm, "gc", functionGCAndSweep, 0);
1254 addFunction(vm, "fullGC", functionFullGC, 0);
1255 addFunction(vm, "edenGC", functionEdenGC, 0);
1256 addFunction(vm, "forceGCSlowPaths", functionForceGCSlowPaths, 0);
1257 addFunction(vm, "gcHeapSize", functionHeapSize, 0);
1258 addFunction(vm, "addressOf", functionAddressOf, 1);
1259 addFunction(vm, "getGetterSetter", functionGetGetterSetter, 2);
1260#ifndef NDEBUG
1261 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
1262#endif
1263 addFunction(vm, "version", functionVersion, 1);
1264 addFunction(vm, "run", functionRun, 1);
1265 addFunction(vm, "runString", functionRunString, 1);
1266 addFunction(vm, "load", functionLoad, 1);
1267 addFunction(vm, "loadString", functionLoadString, 1);
1268 addFunction(vm, "readFile", functionReadFile, 2);
1269 addFunction(vm, "read", functionReadFile, 2);
1270 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
1271 addFunction(vm, "sleepSeconds", functionSleepSeconds, 1);
1272 addFunction(vm, "jscStack", functionJSCStack, 1);
1273 addFunction(vm, "readline", functionReadline, 0);
1274 addFunction(vm, "preciseTime", functionPreciseTime, 0);
1275 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
1276 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
1277 addFunction(vm, "noDFG", functionNoDFG, 1);
1278 addFunction(vm, "noFTL", functionNoFTL, 1);
1279 addFunction(vm, "noOSRExitFuzzing", functionNoOSRExitFuzzing, 1);
1280 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
1281 addFunction(vm, "jscOptions", functionJSCOptions, 0);
1282 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
1283 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
1284 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
1285 addFunction(vm, "failNextNewCodeBlock", functionFailNextNewCodeBlock, 1);
1286#if ENABLE(SAMPLING_FLAGS)
1287 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
1288 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
1289#endif
1290 addFunction(vm, "shadowChickenFunctionsOnStack", functionShadowChickenFunctionsOnStack, 0);
1291 addFunction(vm, "setGlobalConstRedeclarationShouldNotThrow", functionSetGlobalConstRedeclarationShouldNotThrow, 0);
1292 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
1293 addConstructableFunction(vm, "Element", functionCreateElement, 1);
1294 addFunction(vm, "getElement", functionGetElement, 1);
1295 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
1296
1297 addConstructableFunction(vm, "SimpleObject", functionCreateSimpleObject, 0);
1298 addFunction(vm, "getHiddenValue", functionGetHiddenValue, 1);
1299 addFunction(vm, "setHiddenValue", functionSetHiddenValue, 2);
1300
1301 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum);
1302 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum);
1303 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum);
1304 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum);
1305 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, DontEnum);
1306 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum);
1307
1308 addFunction(vm, "effectful42", functionEffectful42, 0);
1309 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
1310 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
1311
1312 addFunction(vm, "createProxy", functionCreateProxy, 1);
1313 addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
1314
1315 addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
1316 addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
1317 addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0);
1318 addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0);
1319 addFunction(vm, "createDOMJITGetterComplexObject", functionCreateDOMJITGetterComplexObject, 0);
1320 addFunction(vm, "createDOMJITFunctionObject", functionCreateDOMJITFunctionObject, 0);
1321 addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
1322 addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
1323 addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
1324
1325 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
1326 addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
1327 addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
1328
1329 addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
1330 addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
1331 addFunction(vm, "basicBlockExecutionCount", functionBasicBlockExecutionCount, 2);
1332
1333 addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
1334
1335 addFunction(vm, "drainMicrotasks", functionDrainMicrotasks, 0);
1336
1337 addFunction(vm, "getRandomSeed", functionGetRandomSeed, 0);
1338 addFunction(vm, "setRandomSeed", functionSetRandomSeed, 1);
1339 addFunction(vm, "isRope", functionIsRope, 1);
1340 addFunction(vm, "callerSourceOrigin", functionCallerSourceOrigin, 0);
1341
1342 addFunction(vm, "globalObjectForObject", functionGlobalObjectForObject, 1);
1343
1344 addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
1345
1346 addFunction(vm, "loadModule", functionLoadModule, 1);
1347 addFunction(vm, "checkModuleSyntax", functionCheckModuleSyntax, 1);
1348
1349 addFunction(vm, "platformSupportsSamplingProfiler", functionPlatformSupportsSamplingProfiler, 0);
1350 addFunction(vm, "generateHeapSnapshot", functionGenerateHeapSnapshot, 0);
1351 addFunction(vm, "resetSuperSamplerState", functionResetSuperSamplerState, 0);
1352 addFunction(vm, "ensureArrayStorage", functionEnsureArrayStorage, 0);
1353#if ENABLE(SAMPLING_PROFILER)
1354 addFunction(vm, "startSamplingProfiler", functionStartSamplingProfiler, 0);
1355 addFunction(vm, "samplingProfilerStackTraces", functionSamplingProfilerStackTraces, 0);
1356#endif
1357
1358 addFunction(vm, "maxArguments", functionMaxArguments, 0);
1359
1360 addFunction(vm, "asyncTestStart", functionAsyncTestStart, 1);
1361 addFunction(vm, "asyncTestPassed", functionAsyncTestPassed, 1);
1362
1363#if ENABLE(WEBASSEMBLY)
1364 addFunction(vm, "testWasmModuleFunctions", functionTestWasmModuleFunctions, 0);
1365 addFunction(vm, "WebAssemblyMemoryMode", functionWebAssemblyMemoryMode, 1);
1366#endif
1367
1368 if (!arguments.isEmpty()) {
1369 JSArray* array = constructEmptyArray(globalExec(), 0);
1370 for (size_t i = 0; i < arguments.size(); ++i)
1371 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
1372 putDirect(vm, Identifier::fromString(globalExec(), "arguments"), array);
1373 }
1374
1375 putDirect(vm, Identifier::fromString(globalExec(), "console"), jsUndefined());
1376
1377 Structure* plainObjectStructure = JSFinalObject::createStructure(vm, this, objectPrototype(), 0);
1378
1379 JSObject* dollar = JSFinalObject::create(vm, plainObjectStructure);
1380 putDirect(vm, Identifier::fromString(globalExec(), "$"), dollar);
1381
1382 addFunction(vm, dollar, "createRealm", functionDollarCreateRealm, 0);
1383 addFunction(vm, dollar, "detachArrayBuffer", functionDollarDetachArrayBuffer, 1);
1384 addFunction(vm, dollar, "evalScript", functionDollarEvalScript, 1);
1385
1386 dollar->putDirect(vm, Identifier::fromString(globalExec(), "global"), this);
1387
1388 JSObject* agent = JSFinalObject::create(vm, plainObjectStructure);
1389 dollar->putDirect(vm, Identifier::fromString(globalExec(), "agent"), agent);
1390
1391 // The test262 INTERPRETING.md document says that some of these functions are just in the main
1392 // thread and some are in the other threads. We just put them in all threads.
1393 addFunction(vm, agent, "start", functionDollarAgentStart, 1);
1394 addFunction(vm, agent, "receiveBroadcast", functionDollarAgentReceiveBroadcast, 1);
1395 addFunction(vm, agent, "report", functionDollarAgentReport, 1);
1396 addFunction(vm, agent, "sleep", functionDollarAgentSleep, 1);
1397 addFunction(vm, agent, "broadcast", functionDollarAgentBroadcast, 1);
1398 addFunction(vm, agent, "getReport", functionDollarAgentGetReport, 0);
1399 addFunction(vm, agent, "leaving", functionDollarAgentLeaving, 0);
1400
1401 addFunction(vm, "waitForReport", functionWaitForReport, 0);
1402
1403 addFunction(vm, "heapCapacity", functionHeapCapacity, 0);
1404 addFunction(vm, "flashHeapAccess", functionFlashHeapAccess, 0);
1405 }
1406
1407 void addFunction(VM& vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments)
1408 {
1409 Identifier identifier = Identifier::fromString(&vm, name);
1410 object->putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
1411 }
1412
1413 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
1414 {
1415 addFunction(vm, this, name, function, arguments);
1416 }
1417
1418 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
1419 {
1420 Identifier identifier = Identifier::fromString(&vm, name);
1421 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
1422 }
1423
1424 static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, ExecState*, JSModuleLoader*, JSString*, const SourceOrigin&);
1425 static JSInternalPromise* moduleLoaderResolve(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
1426 static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue);
1427};
1428
1429const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, nullptr, CREATE_METHOD_TABLE(GlobalObject) };
1430const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = {
1431 &supportsRichSourceInfo,
1432 &shouldInterruptScript,
1433 &javaScriptRuntimeFlags,
1434 nullptr,
1435 &shouldInterruptScriptBeforeTimeout,
1436 &moduleLoaderImportModule,
1437 &moduleLoaderResolve,
1438 &moduleLoaderFetch,
1439 nullptr,
1440 nullptr,
1441 nullptr
1442};
1443
1444GlobalObject::GlobalObject(VM& vm, Structure* structure)
1445 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
1446{
1447}
1448
1449static UChar pathSeparator()
1450{
1451#if OS(WINDOWS)
1452 return '\\';
1453#else
1454 return '/';
1455#endif
1456}
1457
1458struct DirectoryName {
1459 // In unix, it is "/". In Windows, it becomes a drive letter like "C:\"
1460 String rootName;
1461
1462 // If the directory name is "/home/WebKit", this becomes "home/WebKit". If the directory name is "/", this becomes "".
1463 String queryName;
1464};
1465
1466struct ModuleName {
1467 ModuleName(const String& moduleName);
1468
1469 bool startsWithRoot() const
1470 {
1471 return !queries.isEmpty() && queries[0].isEmpty();
1472 }
1473
1474 Vector<String> queries;
1475};
1476
1477ModuleName::ModuleName(const String& moduleName)
1478{
1479 // A module name given from code is represented as the UNIX style path. Like, `./A/B.js`.
1480 moduleName.split('/', true, queries);
1481}
1482
1483static std::optional<DirectoryName> extractDirectoryName(const String& absolutePathToFile)
1484{
1485 size_t firstSeparatorPosition = absolutePathToFile.find(pathSeparator());
1486 if (firstSeparatorPosition == notFound)
1487 return std::nullopt;
1488 DirectoryName directoryName;
1489 directoryName.rootName = absolutePathToFile.substring(0, firstSeparatorPosition + 1); // Include the separator.
1490 size_t lastSeparatorPosition = absolutePathToFile.reverseFind(pathSeparator());
1491 ASSERT_WITH_MESSAGE(lastSeparatorPosition != notFound, "If the separator is not found, this function already returns when performing the forward search.");
1492 if (firstSeparatorPosition == lastSeparatorPosition)
1493 directoryName.queryName = StringImpl::empty();
1494 else {
1495 size_t queryStartPosition = firstSeparatorPosition + 1;
1496 size_t queryLength = lastSeparatorPosition - queryStartPosition; // Not include the last separator.
1497 directoryName.queryName = absolutePathToFile.substring(queryStartPosition, queryLength);
1498 }
1499 return directoryName;
1500}
1501
1502static std::optional<DirectoryName> currentWorkingDirectory()
1503{
1504#if OS(WINDOWS)
1505 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364934.aspx
1506 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
1507 // The _MAX_PATH in Windows is 260. If the path of the current working directory is longer than that, _getcwd truncates the result.
1508 // And other I/O functions taking a path name also truncate it. To avoid this situation,
1509 //
1510 // (1). When opening the file in Windows for modules, we always use the abosolute path and add "\\?\" prefix to the path name.
1511 // (2). When retrieving the current working directory, use GetCurrentDirectory instead of _getcwd.
1512 //
1513 // In the path utility functions inside the JSC shell, we does not handle the UNC and UNCW including the network host name.
1514 DWORD bufferLength = ::GetCurrentDirectoryW(0, nullptr);
1515 if (!bufferLength)
1516 return std::nullopt;
1517 // In Windows, wchar_t is the UTF-16LE.
1518 // https://msdn.microsoft.com/en-us/library/dd374081.aspx
1519 // https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407.aspx
1520 auto buffer = std::make_unique<wchar_t[]>(bufferLength);
1521 DWORD lengthNotIncludingNull = ::GetCurrentDirectoryW(bufferLength, buffer.get());
1522 static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
1523 String directoryString = String(reinterpret_cast<UChar*>(buffer.get()));
1524 // We don't support network path like \\host\share\<path name>.
1525 if (directoryString.startsWith("\\\\"))
1526 return std::nullopt;
1527#else
1528 auto buffer = std::make_unique<char[]>(PATH_MAX);
1529 if (!getcwd(buffer.get(), PATH_MAX))
1530 return std::nullopt;
1531 String directoryString = String::fromUTF8(buffer.get());
1532#endif
1533 if (directoryString.isEmpty())
1534 return std::nullopt;
1535
1536 if (directoryString[directoryString.length() - 1] == pathSeparator())
1537 return extractDirectoryName(directoryString);
1538 // Append the seperator to represents the file name. extractDirectoryName only accepts the absolute file name.
1539 return extractDirectoryName(makeString(directoryString, pathSeparator()));
1540}
1541
1542static String resolvePath(const DirectoryName& directoryName, const ModuleName& moduleName)
1543{
1544 Vector<String> directoryPieces;
1545 directoryName.queryName.split(pathSeparator(), false, directoryPieces);
1546
1547 // Only first '/' is recognized as the path from the root.
1548 if (moduleName.startsWithRoot())
1549 directoryPieces.clear();
1550
1551 for (const auto& query : moduleName.queries) {
1552 if (query == String(ASCIILiteral(".."))) {
1553 if (!directoryPieces.isEmpty())
1554 directoryPieces.removeLast();
1555 } else if (!query.isEmpty() && query != String(ASCIILiteral(".")))
1556 directoryPieces.append(query);
1557 }
1558
1559 StringBuilder builder;
1560 builder.append(directoryName.rootName);
1561 for (size_t i = 0; i < directoryPieces.size(); ++i) {
1562 builder.append(directoryPieces[i]);
1563 if (i + 1 != directoryPieces.size())
1564 builder.append(pathSeparator());
1565 }
1566 return builder.toString();
1567}
1568
1569static String absolutePath(const String& fileName)
1570{
1571 auto directoryName = currentWorkingDirectory();
1572 if (!directoryName)
1573 return fileName;
1574 return resolvePath(directoryName.value(), ModuleName(fileName.impl()));
1575}
1576
1577JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSString* moduleNameValue, const SourceOrigin& sourceOrigin)
1578{
1579 VM& vm = globalObject->vm();
1580 auto scope = DECLARE_CATCH_SCOPE(vm);
1581
1582 auto rejectPromise = [&] (JSValue error) {
1583 return JSInternalPromiseDeferred::create(exec, globalObject)->reject(exec, error);
1584 };
1585
1586 if (sourceOrigin.isNull())
1587 return rejectPromise(createError(exec, ASCIILiteral("Could not resolve the module specifier.")));
1588
1589 auto referrer = sourceOrigin.string();
1590 auto moduleName = moduleNameValue->value(exec);
1591 if (UNLIKELY(scope.exception())) {
1592 JSValue exception = scope.exception();
1593 scope.clearException();
1594 return rejectPromise(exception);
1595 }
1596
1597 auto directoryName = extractDirectoryName(referrer.impl());
1598 if (!directoryName)
1599 return rejectPromise(createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
1600
1601 return JSC::importModule(exec, Identifier::fromString(&vm, resolvePath(directoryName.value(), ModuleName(moduleName))), jsUndefined());
1602}
1603
1604JSInternalPromise* GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue)
1605{
1606 VM& vm = globalObject->vm();
1607 auto scope = DECLARE_CATCH_SCOPE(vm);
1608
1609 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1610 RELEASE_ASSERT(!scope.exception());
1611 const Identifier key = keyValue.toPropertyKey(exec);
1612 if (UNLIKELY(scope.exception())) {
1613 JSValue exception = scope.exception();
1614 scope.clearException();
1615 return deferred->reject(exec, exception);
1616 }
1617
1618 if (key.isSymbol())
1619 return deferred->resolve(exec, keyValue);
1620
1621 if (referrerValue.isUndefined()) {
1622 auto directoryName = currentWorkingDirectory();
1623 if (!directoryName)
1624 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1625 return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
1626 }
1627
1628 const Identifier referrer = referrerValue.toPropertyKey(exec);
1629 if (UNLIKELY(scope.exception())) {
1630 JSValue exception = scope.exception();
1631 scope.clearException();
1632 return deferred->reject(exec, exception);
1633 }
1634
1635 if (referrer.isSymbol()) {
1636 auto directoryName = currentWorkingDirectory();
1637 if (!directoryName)
1638 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1639 return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
1640 }
1641
1642 // If the referrer exists, we assume that the referrer is the correct absolute path.
1643 auto directoryName = extractDirectoryName(referrer.impl());
1644 if (!directoryName)
1645 return deferred->reject(exec, createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
1646 auto result = deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
1647 RELEASE_ASSERT(!scope.exception());
1648 return result;
1649}
1650
1651static void convertShebangToJSComment(Vector<char>& buffer)
1652{
1653 if (buffer.size() >= 2) {
1654 if (buffer[0] == '#' && buffer[1] == '!')
1655 buffer[0] = buffer[1] = '/';
1656 }
1657}
1658
1659static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
1660{
1661 // We might have injected "use strict"; at the top.
1662 size_t initialSize = buffer.size();
1663 fseek(file, 0, SEEK_END);
1664 size_t bufferCapacity = ftell(file);
1665 fseek(file, 0, SEEK_SET);
1666 buffer.resize(bufferCapacity + initialSize);
1667 size_t readSize = fread(buffer.data() + initialSize, 1, buffer.size(), file);
1668 return readSize == buffer.size() - initialSize;
1669}
1670
1671static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1672{
1673 FILE* f = fopen(fileName.utf8().data(), "rb");
1674 if (!f) {
1675 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1676 return false;
1677 }
1678
1679 bool result = fillBufferWithContentsOfFile(f, buffer);
1680 fclose(f);
1681
1682 return result;
1683}
1684
1685static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1686{
1687 if (!fillBufferWithContentsOfFile(fileName, buffer))
1688 return false;
1689 convertShebangToJSComment(buffer);
1690 return true;
1691}
1692
1693static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1694{
1695 // We assume that fileName is always an absolute path.
1696#if OS(WINDOWS)
1697 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
1698 // Use long UNC to pass the long path name to the Windows APIs.
1699 String longUNCPathName = WTF::makeString("\\\\?\\", fileName);
1700 static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
1701 auto utf16Vector = longUNCPathName.charactersWithNullTermination();
1702 FILE* f = _wfopen(reinterpret_cast<wchar_t*>(utf16Vector.data()), L"rb");
1703#else
1704 FILE* f = fopen(fileName.utf8().data(), "r");
1705#endif
1706 if (!f) {
1707 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1708 return false;
1709 }
1710
1711 bool result = fillBufferWithContentsOfFile(f, buffer);
1712 if (result)
1713 convertShebangToJSComment(buffer);
1714 fclose(f);
1715
1716 return result;
1717}
1718
1719JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSValue)
1720{
1721 VM& vm = globalObject->vm();
1722 auto scope = DECLARE_CATCH_SCOPE(vm);
1723 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1724 String moduleKey = key.toWTFString(exec);
1725 if (UNLIKELY(scope.exception())) {
1726 JSValue exception = scope.exception();
1727 scope.clearException();
1728 return deferred->reject(exec, exception);
1729 }
1730
1731 // Here, now we consider moduleKey as the fileName.
1732 Vector<char> utf8;
1733 if (!fetchModuleFromLocalFileSystem(moduleKey, utf8))
1734 return deferred->reject(exec, createError(exec, makeString("Could not open file '", moduleKey, "'.")));
1735
1736 auto result = deferred->resolve(exec, JSSourceCode::create(exec->vm(), makeSource(stringFromUTF(utf8), SourceOrigin { moduleKey }, moduleKey, TextPosition(), SourceProviderSourceType::Module)));
1737 RELEASE_ASSERT(!scope.exception());
1738 return result;
1739}
1740
1741
1742static EncodedJSValue printInternal(ExecState* exec, FILE* out)
1743{
1744 VM& vm = exec->vm();
1745 auto scope = DECLARE_THROW_SCOPE(vm);
1746
1747 if (asyncTestExpectedPasses) {
1748 JSValue value = exec->argument(0);
1749 if (value.isString() && WTF::equal(asString(value)->value(exec).impl(), "Test262:AsyncTestComplete")) {
1750 asyncTestPasses++;
1751 return JSValue::encode(jsUndefined());
1752 }
1753 }
1754
1755 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1756 if (i)
1757 if (EOF == fputc(' ', out))
1758 goto fail;
1759
1760 auto viewWithString = exec->uncheckedArgument(i).toString(exec)->viewWithUnderlyingString(*exec);
1761 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1762 if (fprintf(out, "%s", viewWithString.view.utf8().data()) < 0)
1763 goto fail;
1764 }
1765
1766 fputc('\n', out);
1767fail:
1768 fflush(out);
1769 return JSValue::encode(jsUndefined());
1770}
1771
1772EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState* exec) { return printInternal(exec, stdout); }
1773EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState* exec) { return printInternal(exec, stderr); }
1774
1775#ifndef NDEBUG
1776EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
1777{
1778 VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
1779 ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
1780 if (callerFrame)
1781 exec->vm().interpreter->dumpCallFrame(callerFrame);
1782 return JSValue::encode(jsUndefined());
1783}
1784#endif
1785
1786EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
1787{
1788 VM& vm = exec->vm();
1789 auto scope = DECLARE_THROW_SCOPE(vm);
1790 auto viewWithString = exec->argument(0).toString(exec)->viewWithUnderlyingString(*exec);
1791 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1792 fprintf(stderr, "--> %s\n", viewWithString.view.utf8().data());
1793 return JSValue::encode(jsUndefined());
1794}
1795
1796EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
1797{
1798 if (exec->argumentCount() < 1)
1799 return JSValue::encode(jsUndefined());
1800 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
1801}
1802
1803EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
1804{
1805 if (exec->argumentCount() < 1)
1806 return JSValue::encode(jsUndefined());
1807 VM& vm = exec->vm();
1808 JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(0));
1809 if (!object)
1810 return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
1811 return JSValue::encode(jsNontrivialString(exec, toString("<Butterfly: ", RawPointer(object->butterfly()), "; public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
1812}
1813
1814EncodedJSValue JSC_HOST_CALL functionSleepSeconds(ExecState* exec)
1815{
1816 VM& vm = exec->vm();
1817 auto scope = DECLARE_THROW_SCOPE(vm);
1818
1819 if (exec->argumentCount() >= 1) {
1820 Seconds seconds = Seconds(exec->argument(0).toNumber(exec));
1821 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1822 sleep(seconds);
1823 }
1824
1825 return JSValue::encode(jsUndefined());
1826}
1827
1828class FunctionJSCStackFunctor {
1829public:
1830 FunctionJSCStackFunctor(StringBuilder& trace)
1831 : m_trace(trace)
1832 {
1833 }
1834
1835 StackVisitor::Status operator()(StackVisitor& visitor) const
1836 {
1837 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
1838 return StackVisitor::Continue;
1839 }
1840
1841private:
1842 StringBuilder& m_trace;
1843};
1844
1845EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
1846{
1847 StringBuilder trace;
1848 trace.appendLiteral("--> Stack trace:\n");
1849
1850 FunctionJSCStackFunctor functor(trace);
1851 exec->iterate(functor);
1852 fprintf(stderr, "%s", trace.toString().utf8().data());
1853 return JSValue::encode(jsUndefined());
1854}
1855
1856EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
1857{
1858 JSLockHolder lock(exec);
1859 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
1860}
1861
1862EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
1863{
1864 VM& vm = exec->vm();
1865 JSLockHolder lock(vm);
1866 auto scope = DECLARE_THROW_SCOPE(vm);
1867
1868 Root* root = jsDynamicCast<Root*>(vm, exec->argument(0));
1869 if (!root)
1870 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Cannot create Element without a Root."))));
1871 return JSValue::encode(Element::create(vm, exec->lexicalGlobalObject(), root));
1872}
1873
1874EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
1875{
1876 JSLockHolder lock(exec);
1877 VM& vm = exec->vm();
1878 Root* root = jsDynamicCast<Root*>(vm, exec->argument(0));
1879 if (!root)
1880 return JSValue::encode(jsUndefined());
1881 Element* result = root->element();
1882 return JSValue::encode(result ? result : jsUndefined());
1883}
1884
1885EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
1886{
1887 JSLockHolder lock(exec);
1888 VM& vm = exec->vm();
1889 Element* element = jsDynamicCast<Element*>(vm, exec->argument(0));
1890 Root* root = jsDynamicCast<Root*>(vm, exec->argument(1));
1891 if (element && root)
1892 element->setRoot(exec->vm(), root);
1893 return JSValue::encode(jsUndefined());
1894}
1895
1896EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec)
1897{
1898 JSLockHolder lock(exec);
1899 return JSValue::encode(SimpleObject::create(exec->vm(), exec->lexicalGlobalObject()));
1900}
1901
1902EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec)
1903{
1904 VM& vm = exec->vm();
1905 JSLockHolder lock(vm);
1906 auto scope = DECLARE_THROW_SCOPE(vm);
1907
1908 SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(vm, exec->argument(0));
1909 if (UNLIKELY(!simpleObject)) {
1910 throwTypeError(exec, scope, ASCIILiteral("Invalid use of getHiddenValue test function"));
1911 return encodedJSValue();
1912 }
1913 return JSValue::encode(simpleObject->hiddenValue());
1914}
1915
1916EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec)
1917{
1918 VM& vm = exec->vm();
1919 JSLockHolder lock(vm);
1920 auto scope = DECLARE_THROW_SCOPE(vm);
1921
1922 SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(vm, exec->argument(0));
1923 if (UNLIKELY(!simpleObject)) {
1924 throwTypeError(exec, scope, ASCIILiteral("Invalid use of setHiddenValue test function"));
1925 return encodedJSValue();
1926 }
1927 JSValue value = exec->argument(1);
1928 simpleObject->setHiddenValue(exec->vm(), value);
1929 return JSValue::encode(jsUndefined());
1930}
1931
1932EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
1933{
1934 JSLockHolder lock(exec);
1935 JSValue target = exec->argument(0);
1936 if (!target.isObject())
1937 return JSValue::encode(jsUndefined());
1938 JSObject* jsTarget = asObject(target.asCell());
1939 Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->getPrototypeDirect(), ImpureProxyType);
1940 JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
1941 return JSValue::encode(proxy);
1942}
1943
1944EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
1945{
1946 JSLockHolder lock(exec);
1947 RuntimeArray* array = RuntimeArray::create(exec);
1948 return JSValue::encode(array);
1949}
1950
1951EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
1952{
1953 JSLockHolder lock(exec);
1954 JSValue target = exec->argument(0);
1955 JSObject* delegate = nullptr;
1956 if (target.isObject())
1957 delegate = asObject(target.asCell());
1958 Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1959 ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
1960 return JSValue::encode(result);
1961}
1962
1963EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec)
1964{
1965 JSLockHolder lock(exec);
1966 Structure* structure = CustomGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1967 CustomGetter* result = CustomGetter::create(exec->vm(), structure);
1968 return JSValue::encode(result);
1969}
1970
1971EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec)
1972{
1973 JSLockHolder lock(exec);
1974 Structure* structure = DOMJITNode::createStructure(exec->vm(), exec->lexicalGlobalObject(), DOMJITGetter::create(exec->vm(), DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull())));
1975 DOMJITNode* result = DOMJITNode::create(exec->vm(), structure);
1976 return JSValue::encode(result);
1977}
1978
1979EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec)
1980{
1981 JSLockHolder lock(exec);
1982 Structure* structure = DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1983 DOMJITGetter* result = DOMJITGetter::create(exec->vm(), structure);
1984 return JSValue::encode(result);
1985}
1986
1987EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec)
1988{
1989 JSLockHolder lock(exec);
1990 Structure* structure = DOMJITGetterComplex::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1991 DOMJITGetterComplex* result = DOMJITGetterComplex::create(exec->vm(), exec->lexicalGlobalObject(), structure);
1992 return JSValue::encode(result);
1993}
1994
1995EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState* exec)
1996{
1997 JSLockHolder lock(exec);
1998 Structure* structure = DOMJITFunctionObject::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1999 DOMJITFunctionObject* result = DOMJITFunctionObject::create(exec->vm(), exec->lexicalGlobalObject(), structure);
2000 return JSValue::encode(result);
2001}
2002
2003EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
2004{
2005 VM& vm = exec->vm();
2006 JSLockHolder lock(vm);
2007 auto scope = DECLARE_THROW_SCOPE(vm);
2008
2009 JSValue base = exec->argument(0);
2010 if (!base.isObject())
2011 return JSValue::encode(jsUndefined());
2012 JSValue delegate = exec->argument(1);
2013 if (!delegate.isObject())
2014 return JSValue::encode(jsUndefined());
2015 ImpureGetter* impureGetter = jsDynamicCast<ImpureGetter*>(vm, asObject(base.asCell()));
2016 if (UNLIKELY(!impureGetter)) {
2017 throwTypeError(exec, scope, ASCIILiteral("argument is not an ImpureGetter"));
2018 return encodedJSValue();
2019 }
2020 impureGetter->setDelegate(vm, asObject(delegate.asCell()));
2021 return JSValue::encode(jsUndefined());
2022}
2023
2024EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
2025{
2026 JSLockHolder lock(exec);
2027 exec->heap()->collectAllGarbage();
2028 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
2029}
2030
2031EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
2032{
2033 JSLockHolder lock(exec);
2034 exec->heap()->collectSync(CollectionScope::Full);
2035 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
2036}
2037
2038EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
2039{
2040 JSLockHolder lock(exec);
2041 exec->heap()->collectSync(CollectionScope::Eden);
2042 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastEdenCollection()));
2043}
2044
2045EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*)
2046{
2047 // It's best for this to be the first thing called in the
2048 // JS program so the option is set to true before we JIT.
2049 Options::forceGCSlowPaths() = true;
2050 return JSValue::encode(jsUndefined());
2051}
2052
2053EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
2054{
2055 JSLockHolder lock(exec);
2056 return JSValue::encode(jsNumber(exec->heap()->size()));
2057}
2058
2059// This function is not generally very helpful in 64-bit code as the tag and payload
2060// share a register. But in 32-bit JITed code the tag may not be checked if an
2061// optimization removes type checking requirements, such as in ===.
2062EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState* exec)
2063{
2064 JSValue value = exec->argument(0);
2065 if (!value.isCell())
2066 return JSValue::encode(jsUndefined());
2067 // Need to cast to uint64_t so bitwise_cast will play along.
2068 uint64_t asNumber = reinterpret_cast<uint64_t>(value.asCell());
2069 EncodedJSValue returnValue = JSValue::encode(jsNumber(bitwise_cast<double>(asNumber)));
2070 return returnValue;
2071}
2072
2073static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState* exec)
2074{
2075 JSValue value = exec->argument(0);
2076 if (!value.isObject())
2077 return JSValue::encode(jsUndefined());
2078
2079 JSValue property = exec->argument(1);
2080 if (!property.isString())
2081 return JSValue::encode(jsUndefined());
2082
2083 PropertySlot slot(value, PropertySlot::InternalMethodType::VMInquiry);
2084 value.getPropertySlot(exec, asString(property)->toIdentifier(exec), slot);
2085
2086 JSValue result;
2087 if (slot.isCacheableGetter())
2088 result = slot.getterSetter();
2089 else
2090 result = jsNull();
2091
2092 return JSValue::encode(result);
2093}
2094
2095EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
2096{
2097 // We need this function for compatibility with the Mozilla JS tests but for now
2098 // we don't actually do any version-specific handling
2099 return JSValue::encode(jsUndefined());
2100}
2101
2102EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
2103{
2104 VM& vm = exec->vm();
2105 auto scope = DECLARE_THROW_SCOPE(vm);
2106
2107 String fileName = exec->argument(0).toWTFString(exec);
2108 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2109 Vector<char> script;
2110 if (!fetchScriptFromLocalFileSystem(fileName, script))
2111 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2112
2113 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
2114
2115 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
2116 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2117 for (unsigned i = 1; i < exec->argumentCount(); ++i) {
2118 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
2119 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2120 }
2121 globalObject->putDirect(
2122 vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
2123
2124 NakedPtr<Exception> exception;
2125 StopWatch stopWatch;
2126 stopWatch.start();
2127 evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), exception);
2128 stopWatch.stop();
2129
2130 if (exception) {
2131 throwException(globalObject->globalExec(), scope, exception);
2132 return JSValue::encode(jsUndefined());
2133 }
2134
2135 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2136}
2137
2138EncodedJSValue JSC_HOST_CALL functionRunString(ExecState* exec)
2139{
2140 VM& vm = exec->vm();
2141 auto scope = DECLARE_THROW_SCOPE(vm);
2142
2143 String source = exec->argument(0).toWTFString(exec);
2144 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2145
2146 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
2147
2148 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
2149 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2150 for (unsigned i = 1; i < exec->argumentCount(); ++i) {
2151 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
2152 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2153 }
2154 globalObject->putDirect(
2155 vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
2156
2157 NakedPtr<Exception> exception;
2158 evaluate(globalObject->globalExec(), makeSource(source, exec->callerSourceOrigin()), JSValue(), exception);
2159
2160 if (exception) {
2161 scope.throwException(globalObject->globalExec(), exception);
2162 return JSValue::encode(jsUndefined());
2163 }
2164
2165 return JSValue::encode(globalObject);
2166}
2167
2168EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
2169{
2170 VM& vm = exec->vm();
2171 auto scope = DECLARE_THROW_SCOPE(vm);
2172
2173 String fileName = exec->argument(0).toWTFString(exec);
2174 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2175 Vector<char> script;
2176 if (!fetchScriptFromLocalFileSystem(fileName, script))
2177 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2178
2179 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2180
2181 NakedPtr<Exception> evaluationException;
2182 JSValue result = evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
2183 if (evaluationException)
2184 throwException(exec, scope, evaluationException);
2185 return JSValue::encode(result);
2186}
2187
2188EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState* exec)
2189{
2190 VM& vm = exec->vm();
2191 auto scope = DECLARE_THROW_SCOPE(vm);
2192
2193 String sourceCode = exec->argument(0).toWTFString(exec);
2194 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2195 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2196
2197 NakedPtr<Exception> evaluationException;
2198 JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
2199 if (evaluationException)
2200 throwException(exec, scope, evaluationException);
2201 return JSValue::encode(result);
2202}
2203
2204EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
2205{
2206 VM& vm = exec->vm();
2207 auto scope = DECLARE_THROW_SCOPE(vm);
2208
2209 String fileName = exec->argument(0).toWTFString(exec);
2210 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2211
2212 bool isBinary = false;
2213 if (exec->argumentCount() > 1) {
2214 String type = exec->argument(1).toWTFString(exec);
2215 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2216 if (type != "binary")
2217 return throwVMError(exec, scope, "Expected 'binary' as second argument.");
2218 isBinary = true;
2219 }
2220
2221 Vector<char> content;
2222 if (!fillBufferWithContentsOfFile(fileName, content))
2223 return throwVMError(exec, scope, "Could not open file.");
2224
2225 if (!isBinary)
2226 return JSValue::encode(jsString(exec, stringFromUTF(content)));
2227
2228 Structure* structure = exec->lexicalGlobalObject()->typedArrayStructure(TypeUint8);
2229 auto length = content.size();
2230 JSObject* result = createUint8TypedArray(exec, structure, ArrayBuffer::createFromBytes(content.releaseBuffer().leakPtr(), length, [] (void* p) { fastFree(p); }), 0, length);
2231 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2232
2233 return JSValue::encode(result);
2234}
2235
2236EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
2237{
2238 VM& vm = exec->vm();
2239 auto scope = DECLARE_THROW_SCOPE(vm);
2240
2241 String fileName = exec->argument(0).toWTFString(exec);
2242 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2243 Vector<char> script;
2244 if (!fetchScriptFromLocalFileSystem(fileName, script))
2245 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2246
2247 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2248
2249 StopWatch stopWatch;
2250 stopWatch.start();
2251
2252 JSValue syntaxException;
2253 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), &syntaxException);
2254 stopWatch.stop();
2255
2256 if (!validSyntax)
2257 throwException(exec, scope, syntaxException);
2258 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2259}
2260
2261#if ENABLE(SAMPLING_FLAGS)
2262EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
2263{
2264 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2265 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
2266 if ((flag >= 1) && (flag <= 32))
2267 SamplingFlags::setFlag(flag);
2268 }
2269 return JSValue::encode(jsNull());
2270}
2271
2272EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
2273{
2274 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2275 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
2276 if ((flag >= 1) && (flag <= 32))
2277 SamplingFlags::clearFlag(flag);
2278 }
2279 return JSValue::encode(jsNull());
2280}
2281#endif
2282
2283EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState* exec)
2284{
2285 return JSValue::encode(exec->vm().shadowChicken().functionsOnStack(exec));
2286}
2287
2288EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState* exec)
2289{
2290 exec->vm().setGlobalConstRedeclarationShouldThrow(false);
2291 return JSValue::encode(jsUndefined());
2292}
2293
2294EncodedJSValue JSC_HOST_CALL functionGetRandomSeed(ExecState* exec)
2295{
2296 return JSValue::encode(jsNumber(exec->lexicalGlobalObject()->weakRandom().seed()));
2297}
2298
2299EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState* exec)
2300{
2301 VM& vm = exec->vm();
2302 auto scope = DECLARE_THROW_SCOPE(vm);
2303
2304 unsigned seed = exec->argument(0).toUInt32(exec);
2305 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2306 exec->lexicalGlobalObject()->weakRandom().setSeed(seed);
2307 return JSValue::encode(jsUndefined());
2308}
2309
2310EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState* exec)
2311{
2312 JSValue argument = exec->argument(0);
2313 if (!argument.isString())
2314 return JSValue::encode(jsBoolean(false));
2315 const StringImpl* impl = asString(argument)->tryGetValueImpl();
2316 return JSValue::encode(jsBoolean(!impl));
2317}
2318
2319EncodedJSValue JSC_HOST_CALL functionCallerSourceOrigin(ExecState* state)
2320{
2321 SourceOrigin sourceOrigin = state->callerSourceOrigin();
2322 if (sourceOrigin.isNull())
2323 return JSValue::encode(jsNull());
2324 return JSValue::encode(jsString(state, sourceOrigin.string()));
2325}
2326
2327EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState* exec)
2328{
2329 JSValue value = exec->argument(0);
2330 RELEASE_ASSERT(value.isObject());
2331 JSGlobalObject* globalObject = jsCast<JSObject*>(value)->globalObject();
2332 RELEASE_ASSERT(globalObject);
2333 return JSValue::encode(globalObject);
2334}
2335
2336EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
2337{
2338 Vector<char, 256> line;
2339 int c;
2340 while ((c = getchar()) != EOF) {
2341 // FIXME: Should we also break on \r?
2342 if (c == '\n')
2343 break;
2344 line.append(c);
2345 }
2346 line.append('\0');
2347 return JSValue::encode(jsString(exec, line.data()));
2348}
2349
2350EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
2351{
2352 return JSValue::encode(jsNumber(currentTime()));
2353}
2354
2355EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
2356{
2357 return JSValue::encode(setNeverInline(exec));
2358}
2359
2360EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState* exec)
2361{
2362 return JSValue::encode(setNeverOptimize(exec));
2363}
2364
2365EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState* exec)
2366{
2367 VM& vm = exec->vm();
2368 if (JSFunction* function = jsDynamicCast<JSFunction*>(vm, exec->argument(0))) {
2369 FunctionExecutable* executable = function->jsExecutable();
2370 executable->setNeverFTLOptimize(true);
2371 }
2372
2373 return JSValue::encode(jsUndefined());
2374}
2375
2376EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState* exec)
2377{
2378 return JSValue::encode(setCannotUseOSRExitFuzzing(exec));
2379}
2380
2381EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
2382{
2383 return JSValue::encode(optimizeNextInvocation(exec));
2384}
2385
2386EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
2387{
2388 return JSValue::encode(numberOfDFGCompiles(exec));
2389}
2390
2391Message::Message(ArrayBufferContents&& contents, int32_t index)
2392 : m_contents(WTFMove(contents))
2393 , m_index(index)
2394{
2395}
2396
2397Message::~Message()
2398{
2399}
2400
2401Worker::Worker(Workers& workers)
2402 : m_workers(workers)
2403{
2404 auto locker = holdLock(m_workers.m_lock);
2405 m_workers.m_workers.append(this);
2406
2407 *currentWorker() = this;
2408}
2409
2410Worker::~Worker()
2411{
2412 auto locker = holdLock(m_workers.m_lock);
2413 RELEASE_ASSERT(isOnList());
2414 remove();
2415}
2416
2417void Worker::enqueue(const AbstractLocker&, RefPtr<Message> message)
2418{
2419 m_messages.append(message);
2420}
2421
2422RefPtr<Message> Worker::dequeue()
2423{
2424 auto locker = holdLock(m_workers.m_lock);
2425 while (m_messages.isEmpty())
2426 m_workers.m_condition.wait(m_workers.m_lock);
2427 return m_messages.takeFirst();
2428}
2429
2430Worker& Worker::current()
2431{
2432 return **currentWorker();
2433}
2434
2435ThreadSpecific<Worker*>& Worker::currentWorker()
2436{
2437 static ThreadSpecific<Worker*>* result;
2438 static std::once_flag flag;
2439 std::call_once(
2440 flag,
2441 [] () {
2442 result = new ThreadSpecific<Worker*>();
2443 });
2444 return *result;
2445}
2446
2447Workers::Workers()
2448{
2449}
2450
2451Workers::~Workers()
2452{
2453 UNREACHABLE_FOR_PLATFORM();
2454}
2455
2456template<typename Func>
2457void Workers::broadcast(const Func& func)
2458{
2459 auto locker = holdLock(m_lock);
2460 for (Worker* worker = m_workers.begin(); worker != m_workers.end(); worker = worker->next()) {
2461 if (worker != &Worker::current())
2462 func(locker, *worker);
2463 }
2464 m_condition.notifyAll();
2465}
2466
2467void Workers::report(String string)
2468{
2469 auto locker = holdLock(m_lock);
2470 m_reports.append(string.isolatedCopy());
2471 m_condition.notifyAll();
2472}
2473
2474String Workers::tryGetReport()
2475{
2476 auto locker = holdLock(m_lock);
2477 if (m_reports.isEmpty())
2478 return String();
2479 return m_reports.takeFirst();
2480}
2481
2482String Workers::getReport()
2483{
2484 auto locker = holdLock(m_lock);
2485 while (m_reports.isEmpty())
2486 m_condition.wait(m_lock);
2487 return m_reports.takeFirst();
2488}
2489
2490Workers& Workers::singleton()
2491{
2492 static Workers* result;
2493 static std::once_flag flag;
2494 std::call_once(
2495 flag,
2496 [] {
2497 result = new Workers();
2498 });
2499 return *result;
2500}
2501
2502EncodedJSValue JSC_HOST_CALL functionDollarCreateRealm(ExecState* exec)
2503{
2504 VM& vm = exec->vm();
2505 GlobalObject* result = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
2506 return JSValue::encode(result->getDirect(vm, Identifier::fromString(exec, "$")));
2507}
2508
2509EncodedJSValue JSC_HOST_CALL functionDollarDetachArrayBuffer(ExecState* exec)
2510{
2511 return functionTransferArrayBuffer(exec);
2512}
2513
2514EncodedJSValue JSC_HOST_CALL functionDollarEvalScript(ExecState* exec)
2515{
2516 VM& vm = exec->vm();
2517 auto scope = DECLARE_THROW_SCOPE(vm);
2518
2519 String sourceCode = exec->argument(0).toWTFString(exec);
2520 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2521
2522 GlobalObject* globalObject = jsDynamicCast<GlobalObject*>(vm,
2523 exec->thisValue().get(exec, Identifier::fromString(exec, "global")));
2524 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2525 if (!globalObject)
2526 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected global to point to a global object"))));
2527
2528 NakedPtr<Exception> evaluationException;
2529 JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
2530 if (evaluationException)
2531 throwException(exec, scope, evaluationException);
2532 return JSValue::encode(result);
2533}
2534
2535EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState* exec)
2536{
2537 VM& vm = exec->vm();
2538 auto scope = DECLARE_THROW_SCOPE(vm);
2539
2540 String sourceCode = exec->argument(0).toWTFString(exec).isolatedCopy();
2541 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2542
2543 Lock didStartLock;
2544 Condition didStartCondition;
2545 bool didStart = false;
2546
2547 ThreadIdentifier thread = createThread(
2548 "JSC Agent",
2549 [sourceCode, &didStartLock, &didStartCondition, &didStart] () {
2550 CommandLine commandLine(0, nullptr);
2551 commandLine.m_interactive = false;
2552 runJSC(
2553 commandLine,
2554 [&] (VM&, GlobalObject* globalObject) {
2555 // Notify the thread that started us that we have registered a worker.
2556 {
2557 auto locker = holdLock(didStartLock);
2558 didStart = true;
2559 didStartCondition.notifyOne();
2560 }
2561
2562 NakedPtr<Exception> evaluationException;
2563 bool success = true;
2564 JSValue result;
2565 result = evaluate(globalObject->globalExec(), makeSource(sourceCode, SourceOrigin(ASCIILiteral("worker"))), JSValue(), evaluationException);
2566 if (evaluationException)
2567 result = evaluationException->value();
2568 checkException(globalObject, true, evaluationException, result, String(), false, false, success);
2569 if (!success)
2570 exit(1);
2571 return success;
2572 });
2573 });
2574 detachThread(thread);
2575
2576 {
2577 auto locker = holdLock(didStartLock);
2578 while (!didStart)
2579 didStartCondition.wait(didStartLock);
2580 }
2581
2582 return JSValue::encode(jsUndefined());
2583}
2584
2585EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState* exec)
2586{
2587 VM& vm = exec->vm();
2588 auto scope = DECLARE_THROW_SCOPE(vm);
2589
2590 JSValue callback = exec->argument(0);
2591 CallData callData;
2592 CallType callType = getCallData(callback, callData);
2593 if (callType == CallType::None)
2594 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected callback"))));
2595
2596 RefPtr<Message> message;
2597 {
2598 ReleaseHeapAccessScope releaseAccess(vm.heap);
2599 message = Worker::current().dequeue();
2600 }
2601
2602 RefPtr<ArrayBuffer> nativeBuffer = ArrayBuffer::create(message->releaseContents());
2603 ArrayBufferSharingMode sharingMode = nativeBuffer->sharingMode();
2604 JSArrayBuffer* jsBuffer = JSArrayBuffer::create(vm, exec->lexicalGlobalObject()->arrayBufferStructure(sharingMode), WTFMove(nativeBuffer));
2605
2606 MarkedArgumentBuffer args;
2607 args.append(jsBuffer);
2608 args.append(jsNumber(message->index()));
2609 return JSValue::encode(call(exec, callback, callType, callData, jsNull(), args));
2610}
2611
2612EncodedJSValue JSC_HOST_CALL functionDollarAgentReport(ExecState* exec)
2613{
2614 VM& vm = exec->vm();
2615 auto scope = DECLARE_THROW_SCOPE(vm);
2616
2617 String report = exec->argument(0).toWTFString(exec);
2618 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2619
2620 Workers::singleton().report(report);
2621
2622 return JSValue::encode(jsUndefined());
2623}
2624
2625EncodedJSValue JSC_HOST_CALL functionDollarAgentSleep(ExecState* exec)
2626{
2627 VM& vm = exec->vm();
2628 auto scope = DECLARE_THROW_SCOPE(vm);
2629
2630 if (exec->argumentCount() >= 1) {
2631 Seconds seconds = Seconds::fromMilliseconds(exec->argument(0).toNumber(exec));
2632 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2633 sleep(seconds);
2634 }
2635 return JSValue::encode(jsUndefined());
2636}
2637
2638EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState* exec)
2639{
2640 VM& vm = exec->vm();
2641 auto scope = DECLARE_THROW_SCOPE(vm);
2642
2643 JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(vm, exec->argument(0));
2644 if (!jsBuffer || !jsBuffer->isShared())
2645 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected SharedArrayBuffer"))));
2646
2647 int32_t index = exec->argument(1).toInt32(exec);
2648 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2649
2650 Workers::singleton().broadcast(
2651 [&] (const AbstractLocker& locker, Worker& worker) {
2652 ArrayBuffer* nativeBuffer = jsBuffer->impl();
2653 ArrayBufferContents contents;
2654 nativeBuffer->transferTo(vm, contents); // "transferTo" means "share" if the buffer is shared.
2655 RefPtr<Message> message = adoptRef(new Message(WTFMove(contents), index));
2656 worker.enqueue(locker, message);
2657 });
2658
2659 return JSValue::encode(jsUndefined());
2660}
2661
2662EncodedJSValue JSC_HOST_CALL functionDollarAgentGetReport(ExecState* exec)
2663{
2664 VM& vm = exec->vm();
2665
2666 String string = Workers::singleton().tryGetReport();
2667 if (!string)
2668 return JSValue::encode(jsNull());
2669
2670 return JSValue::encode(jsString(&vm, string));
2671}
2672
2673EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*)
2674{
2675 return JSValue::encode(jsUndefined());
2676}
2677
2678EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState* exec)
2679{
2680 VM& vm = exec->vm();
2681
2682 String string;
2683 {
2684 ReleaseHeapAccessScope releaseAccess(vm.heap);
2685 string = Workers::singleton().getReport();
2686 }
2687 if (!string)
2688 return JSValue::encode(jsNull());
2689
2690 return JSValue::encode(jsString(&vm, string));
2691}
2692
2693EncodedJSValue JSC_HOST_CALL functionHeapCapacity(ExecState* exec)
2694{
2695 VM& vm = exec->vm();
2696 return JSValue::encode(jsNumber(vm.heap.capacity()));
2697}
2698
2699EncodedJSValue JSC_HOST_CALL functionFlashHeapAccess(ExecState* exec)
2700{
2701 VM& vm = exec->vm();
2702 auto scope = DECLARE_THROW_SCOPE(vm);
2703
2704 vm.heap.releaseAccess();
2705 if (exec->argumentCount() >= 1) {
2706 double ms = exec->argument(0).toNumber(exec);
2707 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2708 sleep(Seconds::fromMilliseconds(ms));
2709 }
2710 vm.heap.acquireAccess();
2711 return JSValue::encode(jsUndefined());
2712}
2713
2714template<typename ValueType>
2715typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, Identifier, ValueType) { }
2716
2717template<typename ValueType>
2718typename std::enable_if<std::is_fundamental<ValueType>::value>::type addOption(VM& vm, JSObject* optionsObject, Identifier identifier, ValueType value)
2719{
2720 optionsObject->putDirect(vm, identifier, JSValue(value));
2721}
2722
2723EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState* exec)
2724{
2725 JSObject* optionsObject = constructEmptyObject(exec);
2726#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
2727 addOption(exec->vm(), optionsObject, Identifier::fromString(exec, #name_), Options::name_());
2728 JSC_OPTIONS(FOR_EACH_OPTION)
2729#undef FOR_EACH_OPTION
2730 return JSValue::encode(optionsObject);
2731}
2732
2733EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
2734{
2735 if (exec->argumentCount() < 1)
2736 return JSValue::encode(jsUndefined());
2737
2738 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
2739 if (!block)
2740 return JSValue::encode(jsNumber(0));
2741
2742 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
2743}
2744
2745EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
2746{
2747 VM& vm = exec->vm();
2748 auto scope = DECLARE_THROW_SCOPE(vm);
2749
2750 if (exec->argumentCount() < 1)
2751 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Not enough arguments"))));
2752
2753 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(vm, exec->argument(0));
2754 if (!buffer)
2755 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected an array buffer"))));
2756
2757 ArrayBufferContents dummyContents;
2758 buffer->impl()->transferTo(vm, dummyContents);
2759
2760 return JSValue::encode(jsUndefined());
2761}
2762
2763EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState* exec)
2764{
2765 exec->vm().setFailNextNewCodeBlock();
2766 return JSValue::encode(jsUndefined());
2767}
2768
2769EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
2770{
2771 jscExit(EXIT_SUCCESS);
2772
2773#if COMPILER(MSVC)
2774 // Without this, Visual Studio will complain that this method does not return a value.
2775 return JSValue::encode(jsUndefined());
2776#endif
2777}
2778
2779EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*)
2780{
2781 CRASH();
2782}
2783
2784EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
2785EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
2786
2787EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
2788EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
2789EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
2790{
2791 for (size_t i = 0; i < exec->argumentCount(); ++i) {
2792 if (!exec->argument(i).isInt32())
2793 return JSValue::encode(jsBoolean(false));
2794 }
2795 return JSValue::encode(jsBoolean(true));
2796}
2797
2798EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
2799
2800EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
2801{
2802 return JSValue::encode(jsNumber(42));
2803}
2804
2805EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
2806{
2807 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
2808}
2809
2810EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
2811{
2812 JSValue value = exec->argument(0);
2813 if (value.isObject())
2814 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
2815 return JSValue::encode(jsBoolean(false));
2816}
2817
2818EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
2819{
2820 exec->vm().dumpTypeProfilerData();
2821 return JSValue::encode(jsUndefined());
2822}
2823
2824EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
2825{
2826 VM& vm = exec->vm();
2827 RELEASE_ASSERT(exec->vm().typeProfiler());
2828 vm.typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
2829
2830 JSValue functionValue = exec->argument(0);
2831 RELEASE_ASSERT(functionValue.isFunction());
2832 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2833
2834 RELEASE_ASSERT(exec->argument(1).isString());
2835 String substring = asString(exec->argument(1))->value(exec);
2836 String sourceCodeText = executable->source().view().toString();
2837 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
2838
2839 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
2840 return JSValue::encode(JSONParse(exec, jsonString));
2841}
2842
2843EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
2844{
2845 VM& vm = exec->vm();
2846 RELEASE_ASSERT(exec->vm().typeProfiler());
2847 vm.typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
2848
2849 JSValue functionValue = exec->argument(0);
2850 RELEASE_ASSERT(functionValue.isFunction());
2851 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2852
2853 unsigned offset = executable->typeProfilingStartOffset();
2854 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
2855 return JSValue::encode(JSONParse(exec, jsonString));
2856}
2857
2858EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
2859{
2860 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
2861 exec->vm().controlFlowProfiler()->dumpData();
2862 return JSValue::encode(jsUndefined());
2863}
2864
2865EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
2866{
2867 VM& vm = exec->vm();
2868 RELEASE_ASSERT(vm.controlFlowProfiler());
2869
2870 JSValue functionValue = exec->argument(0);
2871 RELEASE_ASSERT(functionValue.isFunction());
2872 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2873
2874 RELEASE_ASSERT(exec->argument(1).isString());
2875 String substring = asString(exec->argument(1))->value(exec);
2876 String sourceCodeText = executable->source().view().toString();
2877 RELEASE_ASSERT(sourceCodeText.contains(substring));
2878 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
2879
2880 bool hasExecuted = vm.controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), vm);
2881 return JSValue::encode(jsBoolean(hasExecuted));
2882}
2883
2884EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec)
2885{
2886 VM& vm = exec->vm();
2887 RELEASE_ASSERT(vm.controlFlowProfiler());
2888
2889 JSValue functionValue = exec->argument(0);
2890 RELEASE_ASSERT(functionValue.isFunction());
2891 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2892
2893 RELEASE_ASSERT(exec->argument(1).isString());
2894 String substring = asString(exec->argument(1))->value(exec);
2895 String sourceCodeText = executable->source().view().toString();
2896 RELEASE_ASSERT(sourceCodeText.contains(substring));
2897 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
2898
2899 size_t executionCount = vm.controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), exec->vm());
2900 return JSValue::encode(JSValue(executionCount));
2901}
2902
2903EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
2904{
2905 Options::useExceptionFuzz() = true;
2906 return JSValue::encode(jsUndefined());
2907}
2908
2909EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState* exec)
2910{
2911 exec->vm().drainMicrotasks();
2912 return JSValue::encode(jsUndefined());
2913}
2914
2915EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*)
2916{
2917#if USE(JSVALUE64)
2918 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
2919#else
2920 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
2921#endif
2922}
2923
2924EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
2925{
2926 VM& vm = exec->vm();
2927 auto scope = DECLARE_THROW_SCOPE(vm);
2928
2929 String fileName = exec->argument(0).toWTFString(exec);
2930 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2931 Vector<char> script;
2932 if (!fetchScriptFromLocalFileSystem(fileName, script))
2933 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2934
2935 JSInternalPromise* promise = loadAndEvaluateModule(exec, fileName);
2936 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2937
2938 JSValue error;
2939 JSFunction* errorHandler = JSNativeStdFunction::create(vm, exec->lexicalGlobalObject(), 1, String(), [&](ExecState* exec) {
2940 error = exec->argument(0);
2941 return JSValue::encode(jsUndefined());
2942 });
2943
2944 promise->then(exec, nullptr, errorHandler);
2945 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2946 vm.drainMicrotasks();
2947 if (error)
2948 return JSValue::encode(throwException(exec, scope, error));
2949 return JSValue::encode(jsUndefined());
2950}
2951
2952EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState* exec)
2953{
2954 VM& vm = exec->vm();
2955 auto scope = DECLARE_THROW_SCOPE(vm);
2956
2957 if (exec->argumentCount() < 1 || !exec->argument(0).isString())
2958 return JSValue::encode(jsUndefined());
2959
2960 String functionText = asString(exec->argument(0))->value(exec);
2961 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2962
2963 const SourceCode& source = makeSource(functionText, { });
2964 JSFunction* func = JSFunction::createBuiltinFunction(vm, createBuiltinExecutable(vm, source, Identifier::fromString(&vm, "foo"), ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, source), exec->lexicalGlobalObject());
2965
2966 return JSValue::encode(func);
2967}
2968
2969EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
2970{
2971 VM& vm = exec->vm();
2972 return JSValue::encode(GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>()));
2973}
2974
2975EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState* exec)
2976{
2977 VM& vm = exec->vm();
2978 auto scope = DECLARE_THROW_SCOPE(vm);
2979
2980 String source = exec->argument(0).toWTFString(exec);
2981 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2982
2983 StopWatch stopWatch;
2984 stopWatch.start();
2985
2986 ParserError error;
2987 bool validSyntax = checkModuleSyntax(exec, makeSource(source, { }, String(), TextPosition(), SourceProviderSourceType::Module), error);
2988 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2989 stopWatch.stop();
2990
2991 if (!validSyntax)
2992 throwException(exec, scope, jsNontrivialString(exec, toString("SyntaxError: ", error.message(), ":", error.line())));
2993 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2994}
2995
2996EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*)
2997{
2998#if ENABLE(SAMPLING_PROFILER)
2999 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
3000#else
3001 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
3002#endif
3003}
3004
3005EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState* exec)
3006{
3007 VM& vm = exec->vm();
3008 JSLockHolder lock(vm);
3009 auto scope = DECLARE_THROW_SCOPE(vm);
3010
3011 HeapSnapshotBuilder snapshotBuilder(exec->vm().ensureHeapProfiler());
3012 snapshotBuilder.buildSnapshot();
3013
3014 String jsonString = snapshotBuilder.json();
3015 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
3016 RELEASE_ASSERT(!scope.exception());
3017 return result;
3018}
3019
3020EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*)
3021{
3022 resetSuperSamplerState();
3023 return JSValue::encode(jsUndefined());
3024}
3025
3026EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState* exec)
3027{
3028 VM& vm = exec->vm();
3029 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
3030 if (JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(0)))
3031 object->ensureArrayStorage(exec->vm());
3032 }
3033 return JSValue::encode(jsUndefined());
3034}
3035
3036#if ENABLE(SAMPLING_PROFILER)
3037EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState* exec)
3038{
3039 SamplingProfiler& samplingProfiler = exec->vm().ensureSamplingProfiler(WTF::Stopwatch::create());
3040 samplingProfiler.noticeCurrentThreadAsJSCExecutionThread();
3041 samplingProfiler.start();
3042 return JSValue::encode(jsUndefined());
3043}
3044
3045EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState* exec)
3046{
3047 VM& vm = exec->vm();
3048 auto scope = DECLARE_THROW_SCOPE(vm);
3049
3050 if (!vm.samplingProfiler())
3051 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Sampling profiler was never started"))));
3052
3053 String jsonString = vm.samplingProfiler()->stackTracesAsJSON();
3054 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
3055 RELEASE_ASSERT(!scope.exception());
3056 return result;
3057}
3058#endif // ENABLE(SAMPLING_PROFILER)
3059
3060EncodedJSValue JSC_HOST_CALL functionMaxArguments(ExecState*)
3061{
3062 return JSValue::encode(jsNumber(JSC::maxArguments));
3063}
3064
3065EncodedJSValue JSC_HOST_CALL functionAsyncTestStart(ExecState* exec)
3066{
3067 VM& vm = exec->vm();
3068 auto scope = DECLARE_THROW_SCOPE(vm);
3069
3070 JSValue numberOfAsyncPasses = exec->argument(0);
3071 if (!numberOfAsyncPasses.isUInt32())
3072 return throwVMError(exec, scope, ASCIILiteral("Expected first argument to a uint32"));
3073
3074 asyncTestExpectedPasses += numberOfAsyncPasses.asUInt32();
3075 return encodedJSUndefined();
3076}
3077
3078EncodedJSValue JSC_HOST_CALL functionAsyncTestPassed(ExecState*)
3079{
3080 asyncTestPasses++;
3081 return encodedJSUndefined();
3082}
3083
3084#if ENABLE(WEBASSEMBLY)
3085
3086static CString valueWithTypeOfWasmValue(ExecState* exec, VM& vm, JSValue value, JSValue wasmValue)
3087{
3088 JSString* type = asString(wasmValue.get(exec, makeIdentifier(vm, "type")));
3089
3090 const String& typeString = type->value(exec);
3091 if (typeString == "i64" || typeString == "i32")
3092 return toCString(typeString, " ", RawPointer(bitwise_cast<void*>(value)));
3093 if (typeString == "f32")
3094 return toCString(typeString, " hex: ", RawPointer(bitwise_cast<void*>(value)), ", float: ", bitwise_cast<float>(static_cast<uint32_t>(JSValue::encode(value))));
3095 return toCString(typeString, " hex: ", RawPointer(bitwise_cast<void*>(value)), ", double: ", bitwise_cast<double>(value));
3096}
3097
3098static JSValue box(ExecState* exec, VM& vm, JSValue wasmValue)
3099{
3100 auto scope = DECLARE_CATCH_SCOPE(vm);
3101
3102 JSString* type = asString(wasmValue.get(exec, makeIdentifier(vm, "type")));
3103 ASSERT_UNUSED(scope, !scope.exception());
3104 JSValue value = wasmValue.get(exec, makeIdentifier(vm, "value"));
3105 ASSERT(!scope.exception());
3106
3107 auto unboxString = [&] (const char* hexFormat, const char* decFormat, auto& result) {
3108 if (!value.isString())
3109 return false;
3110
3111 const char* str = toCString(asString(value)->value(exec)).data();
3112 int scanResult;
3113 int length = std::strlen(str);
3114 if ((length > 2 && (str[0] == '0' && str[1] == 'x'))
3115 || (length > 3 && (str[0] == '-' && str[1] == '0' && str[2] == 'x')))
3116#if COMPILER(CLANG)
3117#pragma clang diagnostic push
3118#pragma clang diagnostic ignored "-Wformat-nonliteral"
3119#endif
3120 scanResult = sscanf(str, hexFormat, &result);
3121 else
3122 scanResult = sscanf(str, decFormat, &result);
3123#if COMPILER(CLANG)
3124#pragma clang diagnostic pop
3125#endif
3126 RELEASE_ASSERT(scanResult != EOF);
3127 return true;
3128 };
3129
3130 const String& typeString = type->value(exec);
3131 if (typeString == "i64") {
3132 int64_t result;
3133 if (!unboxString("%llx", "%lld", result))
3134 CRASH();
3135 return JSValue::decode(result);
3136 }
3137
3138 if (typeString == "i32") {
3139 int32_t result;
3140 if (!unboxString("%x", "%d", result))
3141 result = value.asInt32();
3142 return JSValue::decode(static_cast<uint32_t>(result));
3143 }
3144
3145 if (typeString == "f32") {
3146 float result;
3147 if (!unboxString("%a", "%f", result))
3148 result = value.toFloat(exec);
3149 return JSValue::decode(bitwise_cast<uint32_t>(result));
3150 }
3151
3152 RELEASE_ASSERT(typeString == "f64");
3153 double result;
3154 if (!unboxString("%la", "%lf", result))
3155 result = value.asNumber();
3156 return JSValue::decode(bitwise_cast<uint64_t>(result));
3157}
3158
3159// FIXME: https://bugs.webkit.org/show_bug.cgi?id=168582.
3160static JSValue callWasmFunction(VM* vm, JSGlobalObject* globalObject, Wasm::Callee* wasmCallee, const ArgList& boxedArgs)
3161{
3162 JSValue firstArgument;
3163 int argCount = 1;
3164 JSValue* remainingArgs = nullptr;
3165 if (boxedArgs.size()) {
3166 remainingArgs = boxedArgs.data();
3167 firstArgument = *remainingArgs;
3168 remainingArgs++;
3169 argCount = boxedArgs.size();
3170 }
3171
3172 ProtoCallFrame protoCallFrame;
3173 protoCallFrame.init(nullptr, globalObject->globalExec()->jsCallee(), firstArgument, argCount, remainingArgs);
3174
3175 return JSValue::decode(vmEntryToWasm(wasmCallee->entrypoint(), vm, &protoCallFrame));
3176}
3177
3178// testWasmModule(JSArrayBufferView source, number functionCount, ...[[WasmValue, [WasmValue]]]) where the ith copy of [[result, [args]]] is a list
3179// of arguments to be passed to the ith wasm function as well as the expected result. WasmValue is an object with "type" and "value" properties.
3180static EncodedJSValue JSC_HOST_CALL functionTestWasmModuleFunctions(ExecState* exec)
3181{
3182 VM& vm = exec->vm();
3183 auto scope = DECLARE_THROW_SCOPE(vm);
3184
3185 if (!Options::useWebAssembly())
3186 return throwVMTypeError(exec, scope, ASCIILiteral("testWasmModule should only be called if the useWebAssembly option is set"));
3187
3188 JSArrayBufferView* source = jsCast<JSArrayBufferView*>(exec->argument(0));
3189 uint32_t functionCount = exec->argument(1).toUInt32(exec);
3190
3191 if (exec->argumentCount() != functionCount + 2)
3192 CRASH();
3193
3194 Ref<Wasm::Plan> plan = adoptRef(*new Wasm::Plan(vm, static_cast<uint8_t*>(source->vector()), source->length(), Wasm::Plan::FullCompile, Wasm::Plan::dontFinalize));
3195 Wasm::ensureWorklist().enqueue(plan.copyRef());
3196 Wasm::ensureWorklist().completePlanSynchronously(plan.get());
3197 if (plan->failed()) {
3198 dataLogLn("failed to parse module: ", plan->errorMessage());
3199 CRASH();
3200 }
3201
3202 if (plan->internalFunctionCount() != functionCount)
3203 CRASH();
3204
3205 Vector<Ref<Wasm::Callee>> jsEntrypointCallees;
3206 Vector<Ref<Wasm::Callee>> wasmEntrypointCallees;
3207 {
3208 unsigned lastIndex = UINT_MAX;
3209 plan->initializeCallees(
3210 [&] (unsigned calleeIndex, Ref<Wasm::Callee>&& jsEntrypointCallee, Ref<Wasm::Callee>&& wasmEntrypointCallee) {
3211 RELEASE_ASSERT(!calleeIndex || (calleeIndex - 1 == lastIndex));
3212 jsEntrypointCallees.append(WTFMove(jsEntrypointCallee));
3213 wasmEntrypointCallees.append(WTFMove(wasmEntrypointCallee));
3214 lastIndex = calleeIndex;
3215 });
3216 }
3217 std::unique_ptr<Wasm::ModuleInformation> moduleInformation = plan->takeModuleInformation();
3218 RELEASE_ASSERT(!moduleInformation->memory);
3219
3220 for (uint32_t i = 0; i < functionCount; ++i) {
3221 JSArray* testCases = jsCast<JSArray*>(exec->argument(i + 2));
3222 for (unsigned testIndex = 0; testIndex < testCases->length(); ++testIndex) {
3223 JSArray* test = jsCast<JSArray*>(testCases->getIndexQuickly(testIndex));
3224 JSObject* result = jsCast<JSObject*>(test->getIndexQuickly(0));
3225 JSArray* arguments = jsCast<JSArray*>(test->getIndexQuickly(1));
3226
3227 MarkedArgumentBuffer boxedArgs;
3228 if (!Wasm::useFastTLSForContext()) {
3229 // When not using fast TLS, the code we emit expects Wasm::Context*
3230 // as the first argument. These tests that this API supports don't ever
3231 // use a Context. So this is just a hack to get it to not barf.
3232 // We really need to remove this API.
3233 boxedArgs.append(jsNumber(0xbadbeef));
3234 }
3235 for (unsigned argIndex = 0; argIndex < arguments->length(); ++argIndex)
3236 boxedArgs.append(box(exec, vm, arguments->getIndexQuickly(argIndex)));
3237
3238 JSValue callResult;
3239 {
3240 auto scope = DECLARE_THROW_SCOPE(vm);
3241 callResult = callWasmFunction(&vm, exec->lexicalGlobalObject(), jsEntrypointCallees[i].ptr(), boxedArgs);
3242 RETURN_IF_EXCEPTION(scope, { });
3243 }
3244 JSValue expected = box(exec, vm, result);
3245 if (callResult != expected) {
3246 dataLog("Arguments: ");
3247 CommaPrinter comma(", ");
3248 for (unsigned argIndex = 0; argIndex < arguments->length(); ++argIndex)
3249 dataLog(comma, valueWithTypeOfWasmValue(exec, vm, boxedArgs.at(argIndex), arguments->getIndexQuickly(argIndex)));
3250 dataLogLn();
3251
3252 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, toCString(" (callResult == ", valueWithTypeOfWasmValue(exec, vm, callResult, result), ", expected == ", valueWithTypeOfWasmValue(exec, vm, expected, result), ")").data());
3253 CRASH();
3254 }
3255 }
3256 }
3257
3258 return encodedJSUndefined();
3259}
3260
3261static EncodedJSValue JSC_HOST_CALL functionWebAssemblyMemoryMode(ExecState* exec)
3262{
3263 VM& vm = exec->vm();
3264 auto scope = DECLARE_THROW_SCOPE(vm);
3265
3266 if (!Options::useWebAssembly())
3267 return throwVMTypeError(exec, scope, ASCIILiteral("WebAssemblyMemoryMode should only be called if the useWebAssembly option is set"));
3268
3269 if (JSObject* object = exec->argument(0).getObject()) {
3270 if (auto* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, object))
3271 return JSValue::encode(jsString(&vm, makeString(memory->memory().mode())));
3272 if (auto* instance = jsDynamicCast<JSWebAssemblyInstance*>(vm, object))
3273 return JSValue::encode(jsString(&vm, makeString(instance->memoryMode())));
3274 }
3275
3276 return throwVMTypeError(exec, scope, ASCIILiteral("WebAssemblyMemoryMode expects either a WebAssembly.Memory or WebAssembly.Instance"));
3277}
3278
3279#endif // ENABLE(WEBASSEBLY)
3280
3281// Use SEH for Release builds only to get rid of the crash report dialog
3282// (luckily the same tests fail in Release and Debug builds so far). Need to
3283// be in a separate main function because the jscmain function requires object
3284// unwinding.
3285
3286#if COMPILER(MSVC) && !defined(_DEBUG)
3287#define TRY __try {
3288#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
3289#else
3290#define TRY
3291#define EXCEPT(x)
3292#endif
3293
3294int jscmain(int argc, char** argv);
3295
3296static double s_desiredTimeout;
3297static double s_timeoutMultiplier = 1.0;
3298
3299static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
3300{
3301 Seconds timeoutDuration(s_desiredTimeout * s_timeoutMultiplier);
3302 sleep(timeoutDuration);
3303 dataLog("Timed out after ", timeoutDuration, " seconds!\n");
3304 CRASH();
3305}
3306
3307static void startTimeoutThreadIfNeeded()
3308{
3309 if (char* timeoutString = getenv("JSCTEST_timeout")) {
3310 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
3311 dataLog("WARNING: timeout string is malformed, got ", timeoutString,
3312 " but expected a number. Not using a timeout.\n");
3313 } else
3314 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
3315 }
3316}
3317
3318int main(int argc, char** argv)
3319{
3320#if PLATFORM(IOS) && CPU(ARM_THUMB2)
3321 // Enabled IEEE754 denormal support.
3322 fenv_t env;
3323 fegetenv( &env );
3324 env.__fpscr &= ~0x01000000u;
3325 fesetenv( &env );
3326#endif
3327
3328#if OS(WINDOWS)
3329 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
3330 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
3331 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
3332 ::SetErrorMode(0);
3333
3334#if defined(_DEBUG)
3335 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
3336 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3337 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
3338 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
3339 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
3340 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
3341#endif
3342
3343 timeBeginPeriod(1);
3344#endif
3345
3346#if PLATFORM(GTK)
3347 if (!setlocale(LC_ALL, ""))
3348 WTFLogAlways("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
3349#endif
3350
3351 // Need to initialize WTF threading before we start any threads. Cannot initialize JSC
3352 // threading yet, since that would do somethings that we'd like to defer until after we
3353 // have a chance to parse options.
3354 WTF::initializeThreading();
3355
3356#if PLATFORM(IOS)
3357 Options::crashIfCantAllocateJITMemory() = true;
3358#endif
3359
3360 // We can't use destructors in the following code because it uses Windows
3361 // Structured Exception Handling
3362 int res = 0;
3363 TRY
3364 res = jscmain(argc, argv);
3365 EXCEPT(res = 3)
3366 finalizeStatsAtEndOfTesting();
3367
3368 jscExit(res);
3369}
3370
3371static void dumpException(GlobalObject* globalObject, JSValue exception)
3372{
3373 VM& vm = globalObject->vm();
3374 auto scope = DECLARE_CATCH_SCOPE(vm);
3375
3376#define CHECK_EXCEPTION() do { \
3377 if (scope.exception()) { \
3378 scope.clearException(); \
3379 return; \
3380 } \
3381 } while (false)
3382
3383 printf("Exception: %s\n", exception.toWTFString(globalObject->globalExec()).utf8().data());
3384
3385 Identifier nameID = Identifier::fromString(globalObject->globalExec(), "name");
3386 CHECK_EXCEPTION();
3387 Identifier fileNameID = Identifier::fromString(globalObject->globalExec(), "sourceURL");
3388 CHECK_EXCEPTION();
3389 Identifier lineNumberID = Identifier::fromString(globalObject->globalExec(), "line");
3390 CHECK_EXCEPTION();
3391 Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
3392 CHECK_EXCEPTION();
3393
3394 JSValue nameValue = exception.get(globalObject->globalExec(), nameID);
3395 CHECK_EXCEPTION();
3396 JSValue fileNameValue = exception.get(globalObject->globalExec(), fileNameID);
3397 CHECK_EXCEPTION();
3398 JSValue lineNumberValue = exception.get(globalObject->globalExec(), lineNumberID);
3399 CHECK_EXCEPTION();
3400 JSValue stackValue = exception.get(globalObject->globalExec(), stackID);
3401 CHECK_EXCEPTION();
3402
3403 if (nameValue.toWTFString(globalObject->globalExec()) == "SyntaxError"
3404 && (!fileNameValue.isUndefinedOrNull() || !lineNumberValue.isUndefinedOrNull())) {
3405 printf(
3406 "at %s:%s\n",
3407 fileNameValue.toWTFString(globalObject->globalExec()).utf8().data(),
3408 lineNumberValue.toWTFString(globalObject->globalExec()).utf8().data());
3409 }
3410
3411 if (!stackValue.isUndefinedOrNull()) {
3412 auto stackString = stackValue.toWTFString(globalObject->globalExec());
3413 if (stackString.length())
3414 printf("%s\n", stackString.utf8().data());
3415 }
3416
3417#undef CHECK_EXCEPTION
3418}
3419
3420static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue exception, const String& expectedExceptionName, bool alwaysDumpException)
3421{
3422 auto scope = DECLARE_CATCH_SCOPE(vm);
3423 scope.clearException();
3424 if (!exception) {
3425 printf("Expected uncaught exception with name '%s' but none was thrown\n", expectedExceptionName.utf8().data());
3426 return false;
3427 }
3428
3429 ExecState* exec = globalObject->globalExec();
3430 JSValue exceptionClass = globalObject->get(exec, Identifier::fromString(exec, expectedExceptionName));
3431 if (!exceptionClass.isObject() || scope.exception()) {
3432 printf("Expected uncaught exception with name '%s' but given exception class is not defined\n", expectedExceptionName.utf8().data());
3433 return false;
3434 }
3435
3436 bool isInstanceOfExpectedException = jsCast<JSObject*>(exceptionClass)->hasInstance(exec, exception);
3437 if (scope.exception()) {
3438 printf("Expected uncaught exception with name '%s' but given exception class fails performing hasInstance\n", expectedExceptionName.utf8().data());
3439 return false;
3440 }
3441 if (isInstanceOfExpectedException) {
3442 if (alwaysDumpException)
3443 dumpException(globalObject, exception);
3444 return true;
3445 }
3446
3447 printf("Expected uncaught exception with name '%s' but exception value is not instance of this exception class\n", expectedExceptionName.utf8().data());
3448 dumpException(globalObject, exception);
3449 return false;
3450}
3451
3452static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool& success)
3453{
3454 VM& vm = globalObject->vm();
3455 if (!uncaughtExceptionName || !isLastFile) {
3456 success = success && !hasException;
3457 if (dump && !hasException)
3458 printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
3459 if (hasException)
3460 dumpException(globalObject, value);
3461 } else
3462 success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
3463}
3464
3465static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool module)
3466{
3467 String fileName;
3468 Vector<char> scriptBuffer;
3469
3470 if (dump)
3471 JSC::Options::dumpGeneratedBytecodes() = true;
3472
3473 VM& vm = globalObject->vm();
3474 auto scope = DECLARE_CATCH_SCOPE(vm);
3475 bool success = true;
3476
3477#if ENABLE(SAMPLING_FLAGS)
3478 SamplingFlags::start();
3479#endif
3480
3481 for (size_t i = 0; i < scripts.size(); i++) {
3482 JSInternalPromise* promise = nullptr;
3483 bool isModule = module || scripts[i].scriptType == Script::ScriptType::Module;
3484 if (scripts[i].codeSource == Script::CodeSource::File) {
3485 fileName = scripts[i].argument;
3486 if (scripts[i].strictMode == Script::StrictMode::Strict)
3487 scriptBuffer.append("\"use strict\";\n", strlen("\"use strict\";\n"));
3488
3489 if (isModule) {
3490 promise = loadAndEvaluateModule(globalObject->globalExec(), fileName);
3491 RELEASE_ASSERT(!scope.exception());
3492 } else {
3493 if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer))
3494 return false; // fail early so we can catch missing files
3495 }
3496 } else {
3497 size_t commandLineLength = strlen(scripts[i].argument);
3498 scriptBuffer.resize(commandLineLength);
3499 std::copy(scripts[i].argument, scripts[i].argument + commandLineLength, scriptBuffer.begin());
3500 fileName = ASCIILiteral("[Command Line]");
3501 }
3502
3503 bool isLastFile = i == scripts.size() - 1;
3504 if (isModule) {
3505 if (!promise)
3506 promise = loadAndEvaluateModule(globalObject->globalExec(), makeSource(stringFromUTF(scriptBuffer), SourceOrigin { absolutePath(fileName) }, fileName, TextPosition(), SourceProviderSourceType::Module));
3507 scope.clearException();
3508
3509 JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
3510 checkException(globalObject, isLastFile, false, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
3511 return JSValue::encode(jsUndefined());
3512 });
3513
3514 JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
3515 checkException(globalObject, isLastFile, true, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
3516 return JSValue::encode(jsUndefined());
3517 });
3518
3519 promise->then(globalObject->globalExec(), fulfillHandler, rejectHandler);
3520 RELEASE_ASSERT(!scope.exception());
3521 vm.drainMicrotasks();
3522 } else {
3523 NakedPtr<Exception> evaluationException;
3524 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
3525 ASSERT(!scope.exception());
3526 if (evaluationException)
3527 returnValue = evaluationException->value();
3528 checkException(globalObject, isLastFile, evaluationException, returnValue, uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
3529 }
3530
3531 scriptBuffer.clear();
3532 scope.clearException();
3533 }
3534
3535#if ENABLE(REGEXP_TRACING)
3536 vm.dumpRegExpTrace();
3537#endif
3538 return success;
3539}
3540
3541#define RUNNING_FROM_XCODE 0
3542
3543static void runInteractive(GlobalObject* globalObject)
3544{
3545 VM& vm = globalObject->vm();
3546 auto scope = DECLARE_CATCH_SCOPE(vm);
3547
3548 std::optional<DirectoryName> directoryName = currentWorkingDirectory();
3549 if (!directoryName)
3550 return;
3551 SourceOrigin sourceOrigin(resolvePath(directoryName.value(), ModuleName("interpreter")));
3552
3553 bool shouldQuit = false;
3554 while (!shouldQuit) {
3555#if HAVE(READLINE) && !RUNNING_FROM_XCODE
3556 ParserError error;
3557 String source;
3558 do {
3559 error = ParserError();
3560 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
3561 shouldQuit = !line;
3562 if (!line)
3563 break;
3564 source = source + line;
3565 source = source + '\n';
3566 checkSyntax(globalObject->vm(), makeSource(source, sourceOrigin), error);
3567 if (!line[0]) {
3568 free(line);
3569 break;
3570 }
3571 add_history(line);
3572 free(line);
3573 } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable);
3574
3575 if (error.isValid()) {
3576 printf("%s:%d\n", error.message().utf8().data(), error.line());
3577 continue;
3578 }
3579
3580
3581 NakedPtr<Exception> evaluationException;
3582 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, sourceOrigin), JSValue(), evaluationException);
3583#else
3584 printf("%s", interactivePrompt);
3585 Vector<char, 256> line;
3586 int c;
3587 while ((c = getchar()) != EOF) {
3588 // FIXME: Should we also break on \r?
3589 if (c == '\n')
3590 break;
3591 line.append(c);
3592 }
3593 if (line.isEmpty())
3594 break;
3595
3596 NakedPtr<Exception> evaluationException;
3597 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, sourceOrigin, sourceOrigin.string()), JSValue(), evaluationException);
3598#endif
3599 if (evaluationException)
3600 printf("Exception: %s\n", evaluationException->value().toWTFString(globalObject->globalExec()).utf8().data());
3601 else
3602 printf("%s\n", returnValue.toWTFString(globalObject->globalExec()).utf8().data());
3603
3604 scope.clearException();
3605 globalObject->vm().drainMicrotasks();
3606 }
3607 printf("\n");
3608}
3609
3610static NO_RETURN void printUsageStatement(bool help = false)
3611{
3612 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
3613 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
3614 fprintf(stderr, " -e Evaluate argument as script code\n");
3615 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
3616 fprintf(stderr, " -h|--help Prints this help message\n");
3617 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
3618 fprintf(stderr, " -m Execute as a module\n");
3619#if HAVE(SIGNAL_H)
3620 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
3621#endif
3622 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
3623 fprintf(stderr, " -x Output exit code before terminating\n");
3624 fprintf(stderr, "\n");
3625 fprintf(stderr, " --sample Collects and outputs sampling profiler data\n");
3626 fprintf(stderr, " --test262-async Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n");
3627 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");
3628 fprintf(stderr, " --module-file=<file> Parse and evaluate the given file as module (this option may be passed more than once)\n");
3629 fprintf(stderr, " --exception=<name> Check the last script exits with an uncaught exception with the specified name\n");
3630 fprintf(stderr, " --dumpException Dump uncaught exception text\n");
3631 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
3632 fprintf(stderr, " --dumpOptions Dumps all non-default JSC VM options before continuing\n");
3633 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
3634 fprintf(stderr, "\n");
3635
3636 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
3637}
3638
3639void CommandLine::parseArguments(int argc, char** argv)
3640{
3641 Options::initialize();
3642
3643 int i = 1;
3644 JSC::Options::DumpLevel dumpOptionsLevel = JSC::Options::DumpLevel::None;
3645 bool needToExit = false;
3646
3647 bool hasBadJSCOptions = false;
3648 for (; i < argc; ++i) {
3649 const char* arg = argv[i];
3650 if (!strcmp(arg, "-f")) {
3651 if (++i == argc)
3652 printUsageStatement();
3653 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
3654 continue;
3655 }
3656 if (!strcmp(arg, "-e")) {
3657 if (++i == argc)
3658 printUsageStatement();
3659 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::CommandLine, Script::ScriptType::Script, argv[i]));
3660 continue;
3661 }
3662 if (!strcmp(arg, "-i")) {
3663 m_interactive = true;
3664 continue;
3665 }
3666 if (!strcmp(arg, "-d")) {
3667 m_dump = true;
3668 continue;
3669 }
3670 if (!strcmp(arg, "-p")) {
3671 if (++i == argc)
3672 printUsageStatement();
3673 m_profile = true;
3674 m_profilerOutput = argv[i];
3675 continue;
3676 }
3677 if (!strcmp(arg, "-m")) {
3678 m_module = true;
3679 continue;
3680 }
3681 if (!strcmp(arg, "-s")) {
3682#if HAVE(SIGNAL_H)
3683 signal(SIGILL, _exit);
3684 signal(SIGFPE, _exit);
3685 signal(SIGBUS, _exit);
3686 signal(SIGSEGV, _exit);
3687#endif
3688 continue;
3689 }
3690 if (!strcmp(arg, "-x")) {
3691 m_exitCode = true;
3692 continue;
3693 }
3694 if (!strcmp(arg, "--")) {
3695 ++i;
3696 break;
3697 }
3698 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
3699 printUsageStatement(true);
3700
3701 if (!strcmp(arg, "--options")) {
3702 dumpOptionsLevel = JSC::Options::DumpLevel::Verbose;
3703 needToExit = true;
3704 continue;
3705 }
3706 if (!strcmp(arg, "--dumpOptions")) {
3707 dumpOptionsLevel = JSC::Options::DumpLevel::Overridden;
3708 continue;
3709 }
3710 if (!strcmp(arg, "--sample")) {
3711 JSC::Options::useSamplingProfiler() = true;
3712 JSC::Options::collectSamplingProfilerDataForJSCShell() = true;
3713 m_dumpSamplingProfilerData = true;
3714 continue;
3715 }
3716
3717 static const char* timeoutMultiplierOptStr = "--timeoutMultiplier=";
3718 static const unsigned timeoutMultiplierOptStrLength = strlen(timeoutMultiplierOptStr);
3719 if (!strncmp(arg, timeoutMultiplierOptStr, timeoutMultiplierOptStrLength)) {
3720 const char* valueStr = &arg[timeoutMultiplierOptStrLength];
3721 if (sscanf(valueStr, "%lf", &s_timeoutMultiplier) != 1)
3722 dataLog("WARNING: --timeoutMultiplier=", valueStr, " is invalid. Expects a numeric ratio.\n");
3723 continue;
3724 }
3725
3726 if (!strcmp(arg, "--test262-async")) {
3727 asyncTestExpectedPasses++;
3728 continue;
3729 }
3730
3731 if (!strcmp(arg, "--remote-debug")) {
3732 m_enableRemoteDebugging = true;
3733 continue;
3734 }
3735
3736 static const unsigned strictFileStrLength = strlen("--strict-file=");
3737 if (!strncmp(arg, "--strict-file=", strictFileStrLength)) {
3738 m_scripts.append(Script(Script::StrictMode::Strict, Script::CodeSource::File, Script::ScriptType::Script, argv[i] + strictFileStrLength));
3739 continue;
3740 }
3741
3742 static const unsigned moduleFileStrLength = strlen("--module-file=");
3743 if (!strncmp(arg, "--module-file=", moduleFileStrLength)) {
3744 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Module, argv[i] + moduleFileStrLength));
3745 continue;
3746 }
3747
3748 if (!strcmp(arg, "--dumpException")) {
3749 m_alwaysDumpUncaughtException = true;
3750 continue;
3751 }
3752
3753 static const unsigned exceptionStrLength = strlen("--exception=");
3754 if (!strncmp(arg, "--exception=", exceptionStrLength)) {
3755 m_uncaughtExceptionName = String(arg + exceptionStrLength);
3756 continue;
3757 }
3758
3759 // See if the -- option is a JSC VM option.
3760 if (strstr(arg, "--") == arg) {
3761 if (!JSC::Options::setOption(&arg[2])) {
3762 hasBadJSCOptions = true;
3763 dataLog("ERROR: invalid option: ", arg, "\n");
3764 }
3765 continue;
3766 }
3767
3768 // This arg is not recognized by the VM nor by jsc. Pass it on to the
3769 // script.
3770 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
3771 }
3772
3773 if (hasBadJSCOptions && JSC::Options::validateOptions())
3774 CRASH();
3775
3776 if (m_scripts.isEmpty())
3777 m_interactive = true;
3778
3779 for (; i < argc; ++i)
3780 m_arguments.append(argv[i]);
3781
3782 if (dumpOptionsLevel != JSC::Options::DumpLevel::None) {
3783 const char* optionsTitle = (dumpOptionsLevel == JSC::Options::DumpLevel::Overridden)
3784 ? "Modified JSC runtime options:"
3785 : "All JSC runtime options:";
3786 JSC::Options::dumpAllOptions(stderr, dumpOptionsLevel, optionsTitle);
3787 }
3788 JSC::Options::ensureOptionsAreCoherent();
3789 if (needToExit)
3790 jscExit(EXIT_SUCCESS);
3791}
3792
3793template<typename Func>
3794int runJSC(CommandLine options, const Func& func)
3795{
3796 Worker worker(Workers::singleton());
3797
3798 VM& vm = VM::create(LargeHeap).leakRef();
3799 int result;
3800 bool success;
3801 {
3802 JSLockHolder locker(vm);
3803
3804 if (options.m_profile && !vm.m_perBytecodeProfiler)
3805 vm.m_perBytecodeProfiler = std::make_unique<Profiler::Database>(vm);
3806
3807 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
3808 globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
3809 success = func(vm, globalObject);
3810 if (options.m_interactive && success)
3811 runInteractive(globalObject);
3812
3813 vm.drainMicrotasks();
3814 }
3815#if USE(CF)
3816 vm.promiseDeferredTimer->runRunLoop();
3817#endif
3818
3819 result = success && (asyncTestExpectedPasses == asyncTestPasses) ? 0 : 3;
3820
3821 if (options.m_exitCode) {
3822 printf("jsc exiting %d", result);
3823 if (asyncTestExpectedPasses != asyncTestPasses)
3824 printf(" because expected: %d async test passes but got: %d async test passes", asyncTestExpectedPasses, asyncTestPasses);
3825 printf("\n");
3826 }
3827
3828 if (options.m_profile) {
3829 JSLockHolder locker(vm);
3830 if (!vm.m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
3831 fprintf(stderr, "could not save profiler output.\n");
3832 }
3833
3834#if ENABLE(JIT)
3835 {
3836 JSLockHolder locker(vm);
3837 if (Options::useExceptionFuzz())
3838 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
3839 bool fireAtEnabled =
3840 Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
3841 if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
3842 printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
3843 if (Options::useOSRExitFuzz()) {
3844 printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks());
3845 printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks());
3846 }
3847
3848
3849 auto compileTimeStats = JIT::compileTimeStats();
3850 Vector<CString> compileTimeKeys;
3851 for (auto& entry : compileTimeStats)
3852 compileTimeKeys.append(entry.key);
3853 std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
3854 for (CString key : compileTimeKeys)
3855 printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
3856 }
3857#endif
3858
3859 if (Options::gcAtEnd()) {
3860 // We need to hold the API lock to do a GC.
3861 JSLockHolder locker(&vm);
3862 vm.heap.collectAllGarbage();
3863 }
3864
3865 if (options.m_dumpSamplingProfilerData) {
3866#if ENABLE(SAMPLING_PROFILER)
3867 JSLockHolder locker(&vm);
3868 vm.samplingProfiler()->reportTopFunctions();
3869 vm.samplingProfiler()->reportTopBytecodes();
3870#else
3871 dataLog("Sampling profiler is not enabled on this platform\n");
3872#endif
3873 }
3874
3875 return result;
3876}
3877
3878int jscmain(int argc, char** argv)
3879{
3880 // Need to override and enable restricted options before we start parsing options below.
3881 Options::enableRestrictedOptions(true);
3882
3883 // Note that the options parsing can affect VM creation, and thus
3884 // comes first.
3885 CommandLine options(argc, argv);
3886
3887 processConfigFile(Options::configFile(), "jsc");
3888
3889 // Initialize JSC before getting VM.
3890 WTF::initializeMainThread();
3891 JSC::initializeThreading();
3892 startTimeoutThreadIfNeeded();
3893#if ENABLE(WEBASSEMBLY)
3894 JSC::Wasm::enableFastMemory();
3895#endif
3896
3897 int result;
3898 result = runJSC(
3899 options,
3900 [&] (VM&, GlobalObject* globalObject) {
3901 return runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
3902 });
3903
3904 printSuperSamplerState();
3905
3906 return result;
3907}
3908
3909#if OS(WINDOWS)
3910extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
3911{
3912 return main(argc, const_cast<char**>(argv));
3913}
3914#endif
Note: See TracBrowser for help on using the repository browser.