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

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

The mutator should be able to perform increments of GC work
https://bugs.webkit.org/show_bug.cgi?id=167528

Reviewed by Keith Miller and Geoffrey Garen.

Source/JavaScriptCore:

The cool thing about having a concurrent and parallel collector is that it's easy to also make
it incremental, because the load balancer can also hand over work to anyone (including the
mutator) and since the collector is running concurrently anyway, the mutator can usually rely
on the balancer having some spare work.

This change adds a classic work-based incremental mode to the GC. When you allocate K bytes,
you have to do Options::gcIncrementScale() * K "bytes" of draining. This is ammortized so that
it only happens in allocation slow paths.

On computers that have a lot of CPUs, this mode is not profitable and we set gcIncrementScale
to zero. On such computers, Riptide was already performing great because there was no way that
one mutator thread could outpace many GC threads. But on computers with fewer CPUs, there were
problems having to do with making the collector progress quickly enough so that the heap
doesn't grow too much. The stochastic scheduler actually made things worse, because it relies
a lot on the fact that the GC will simply be faster than the mutator anyway. The old scheduler
claimed to address the problem of GC pace, but it used a time-based scheduler, which is not as
precise at keeping pase as the new work-based incremental mode.

In theory, the work-based mode guarantees a bound on how much the heap can grow during a
collection just because each byte allocated means some number of bytes visited. We don't try
to create such a theoretical bound. We're just trying to give the collector an unfair advantage
in any race with the mutator.

Turning on incremental mode, the stochastic scheduler, and passive draining in combination with
each other is a huge splay-latency speed-up on my iPad. It's also a CDjs progression. It does
regress splay-throughput, but I think that's fine (the regression is 11%, the progression is
3x).

  • heap/Heap.cpp:

(JSC::Heap::Heap):
(JSC::Heap::~Heap):
(JSC::Heap::markToFixpoint):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::endMarking):
(JSC::Heap::finalize):
(JSC::Heap::didAllocate):
(JSC::Heap::visitCount):
(JSC::Heap::bytesVisited):
(JSC::Heap::forEachSlotVisitor):
(JSC::Heap::performIncrement):
(JSC::Heap::threadVisitCount): Deleted.
(JSC::Heap::threadBytesVisited): Deleted.

  • heap/Heap.h:
  • heap/MarkStack.cpp:

(JSC::MarkStackArray::transferTo):

  • heap/MarkStack.h:
  • heap/SlotVisitor.cpp:

(JSC::SlotVisitor::didStartMarking):
(JSC::SlotVisitor::clearMarkStacks):
(JSC::SlotVisitor::appendToMarkStack):
(JSC::SlotVisitor::noteLiveAuxiliaryCell):
(JSC::SlotVisitor::donateKnownParallel):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::performIncrementOfDraining):
(JSC::SlotVisitor::didReachTermination):
(JSC::SlotVisitor::hasWork):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::correspondingGlobalStack):

  • heap/SlotVisitor.h:
  • heap/SlotVisitorInlines.h:

(JSC::SlotVisitor::reportExtraMemoryVisited):
(JSC::SlotVisitor::forEachMarkStack):

  • heap/SpaceTimeMutatorScheduler.cpp:

(JSC::SpaceTimeMutatorScheduler::log):

  • heap/StochasticSpaceTimeMutatorScheduler.cpp:

(JSC::StochasticSpaceTimeMutatorScheduler::log):

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionHeapCapacity):

  • runtime/Options.cpp:

(JSC::overrideDefaults):

  • runtime/Options.h:

Source/WTF:

We want dataLog to be locked even if you're not logging to a file!

  • wtf/DataLog.cpp:

(WTF::initializeLogFileOnce):

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