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

Last change on this file since 217037 was 217037, checked in by Yusuke Suzuki, 8 years ago

Unreviewed, fix debug and non-JIT build
https://bugs.webkit.org/show_bug.cgi?id=172098

  • jsc.cpp:

(WTF::DOMJITFunctionObject::checkSubClassPatchpoint):

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