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

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

Add support for Error.stackTraceLimit.
https://bugs.webkit.org/show_bug.cgi?id=169904

Reviewed by Saam Barati.

JSTests:

  • stress/error-stack-trace-limit.js: Added.

Source/JavaScriptCore:

Since there's no standard for this yet, we'll implement Error.stackTraceLimit
based on how Chrome does it. This includes some idiosyncrasies like:

  1. If we set Error.stackTraceLimit = 0, then new Error().stack yields an empty stack trace (Chrome has a title with no stack frame entries).
  2. If we set Error.stackTraceLimit = {] (i.e. to a non-number value), then new Error().stack is undefined.

Chrome and IE defaults their Error.stackTraceLimit to 10. We'll default ours to
100 because 10 may be a bit too skimpy and it is not that costly to allow up to
100 frames instead of 10.

The default value for Error.stackTraceLimit is specified by
Options::defaultErrorStackTraceLimit().

Also, the Exception object now limits the number of stack trace frames it captures
to the limit specified by Options::exceptionStackTraceLimit().

Note: the Exception object captures a stack trace that is not necessarily the
same as the one in an Error object being thrown:

  • The Error object captures the stack trace at the point of object creation.
  • The Exception object captures the stack trace at the point that the exception is thrown. This stack trace is captured even when throwing a value that is not an Error object e.g. a primitive value. The Exception object stack trace is only used by WebInspector to identify where a value is thrown from. Hence, it does not necessary make sense the Exception object stack trace limited by Error.stackTraceLimit. Instead, we have it use own Options::exceptionStackTraceLimit().
  • interpreter/Interpreter.cpp:

(JSC::Interpreter::unwind):

  • jsc.cpp:

(dumpException):

  • runtime/CommonIdentifiers.h:
  • runtime/Error.cpp:

(JSC::addErrorInfoAndGetBytecodeOffset):

  • runtime/ErrorConstructor.cpp:

(JSC::ErrorConstructor::finishCreation):
(JSC::ErrorConstructor::put):
(JSC::ErrorConstructor::deleteProperty):

  • runtime/ErrorConstructor.h:

(JSC::ErrorConstructor::stackTraceLimit):

  • runtime/Exception.cpp:

(JSC::Exception::finishCreation):

  • runtime/Options.h:

LayoutTests:

Rebased test.

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