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

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

Web Inspector: allow import() inside the inspector
https://bugs.webkit.org/show_bug.cgi?id=167457

Reviewed by Ryosuke Niwa.

Source/JavaScriptCore:

We relax import module hook to accept null SourceOrigin.
Such a script can be evaluated from the inspector console.

  • jsc.cpp:

(GlobalObject::moduleLoaderImportModule):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncImportModule):

Source/WebCore:

When evaluating import("..."), we need the caller's context to resolve
the module specifier correctly. For example, if import("./cocoa.js") is
evaluated in the script "drinks/hot.js", this module name is resolved to
"drinks/cocoa.js". If the same import operator is evaluated in the script
"menu/all.js", the module specifier becomes "menu/cocoa.js".

Previously we reject the import operator if the caller does not have such
a context. These context is SourceOrigin and its ScriptFetcher. While they
are offered in the script tag and other code evaluations, the inspector
console does not offer that. These class are offered in the WebCore side
and we should not touch these classes in the JSC's inspector code.

Now we relax the above restriction. If the above caller information is not
offered, we fallback to the default one. In the web page, we use the page's
URL as the caller's source origin. This allows us to evaluate the import
operator in the inspector console.

And as of r167698, the console recognizes await import("...") form. We use
this to test this import() in the console functionality.

Test: inspector/controller/runtime-controller-import.html

  • bindings/js/ScriptModuleLoader.cpp:

(WebCore::ScriptModuleLoader::importModule):

LayoutTests:

Extract the test to single file. And make it deterministic.

  • inspector/controller/resources/cappuccino.js: Added.
  • inspector/controller/resources/cocoa.js: Added.
  • inspector/controller/resources/drink.js: Added.
  • inspector/controller/runtime-controller-import-expected.txt: Added.
  • inspector/controller/runtime-controller-import.html: Added.
  • Property svn:eol-style set to native
File size: 138.1 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
4 * Copyright (C) 2006 Bjoern Graf ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24
25#include "ArrayBuffer.h"
26#include "ArrayPrototype.h"
27#include "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 if (sourceOrigin.isNull())
1555 return rejectPromise(createError(exec, ASCIILiteral("Could not resolve the module specifier.")));
1556
1557 auto referrer = sourceOrigin.string();
1558 auto moduleName = moduleNameValue->value(exec);
1559 if (UNLIKELY(scope.exception())) {
1560 JSValue exception = scope.exception();
1561 scope.clearException();
1562 return rejectPromise(exception);
1563 }
1564
1565 auto directoryName = extractDirectoryName(referrer.impl());
1566 if (!directoryName)
1567 return rejectPromise(createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
1568
1569 return JSC::importModule(exec, Identifier::fromString(&vm, resolvePath(directoryName.value(), ModuleName(moduleName))), jsUndefined());
1570}
1571
1572JSInternalPromise* GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue)
1573{
1574 VM& vm = globalObject->vm();
1575 auto scope = DECLARE_CATCH_SCOPE(vm);
1576
1577 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1578 const Identifier key = keyValue.toPropertyKey(exec);
1579 if (UNLIKELY(scope.exception())) {
1580 JSValue exception = scope.exception();
1581 scope.clearException();
1582 return deferred->reject(exec, exception);
1583 }
1584
1585 if (key.isSymbol())
1586 return deferred->resolve(exec, keyValue);
1587
1588 if (referrerValue.isUndefined()) {
1589 auto directoryName = currentWorkingDirectory();
1590 if (!directoryName)
1591 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1592 return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
1593 }
1594
1595 const Identifier referrer = referrerValue.toPropertyKey(exec);
1596 if (UNLIKELY(scope.exception())) {
1597 JSValue exception = scope.exception();
1598 scope.clearException();
1599 return deferred->reject(exec, exception);
1600 }
1601
1602 if (referrer.isSymbol()) {
1603 auto directoryName = currentWorkingDirectory();
1604 if (!directoryName)
1605 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1606 return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
1607 }
1608
1609 // If the referrer exists, we assume that the referrer is the correct absolute path.
1610 auto directoryName = extractDirectoryName(referrer.impl());
1611 if (!directoryName)
1612 return deferred->reject(exec, createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
1613 return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
1614}
1615
1616static void convertShebangToJSComment(Vector<char>& buffer)
1617{
1618 if (buffer.size() >= 2) {
1619 if (buffer[0] == '#' && buffer[1] == '!')
1620 buffer[0] = buffer[1] = '/';
1621 }
1622}
1623
1624static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
1625{
1626 // We might have injected "use strict"; at the top.
1627 size_t initialSize = buffer.size();
1628 fseek(file, 0, SEEK_END);
1629 size_t bufferCapacity = ftell(file);
1630 fseek(file, 0, SEEK_SET);
1631 buffer.resize(bufferCapacity + initialSize);
1632 size_t readSize = fread(buffer.data() + initialSize, 1, buffer.size(), file);
1633 return readSize == buffer.size() - initialSize;
1634}
1635
1636static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1637{
1638 FILE* f = fopen(fileName.utf8().data(), "rb");
1639 if (!f) {
1640 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1641 return false;
1642 }
1643
1644 bool result = fillBufferWithContentsOfFile(f, buffer);
1645 fclose(f);
1646
1647 return result;
1648}
1649
1650static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1651{
1652 if (!fillBufferWithContentsOfFile(fileName, buffer))
1653 return false;
1654 convertShebangToJSComment(buffer);
1655 return true;
1656}
1657
1658static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1659{
1660 // We assume that fileName is always an absolute path.
1661#if OS(WINDOWS)
1662 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
1663 // Use long UNC to pass the long path name to the Windows APIs.
1664 String longUNCPathName = WTF::makeString("\\\\?\\", fileName);
1665 static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
1666 auto utf16Vector = longUNCPathName.charactersWithNullTermination();
1667 FILE* f = _wfopen(reinterpret_cast<wchar_t*>(utf16Vector.data()), L"rb");
1668#else
1669 FILE* f = fopen(fileName.utf8().data(), "r");
1670#endif
1671 if (!f) {
1672 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1673 return false;
1674 }
1675
1676 bool result = fillBufferWithContentsOfFile(f, buffer);
1677 if (result)
1678 convertShebangToJSComment(buffer);
1679 fclose(f);
1680
1681 return result;
1682}
1683
1684JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSValue)
1685{
1686 VM& vm = globalObject->vm();
1687 auto scope = DECLARE_CATCH_SCOPE(vm);
1688 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1689 String moduleKey = key.toWTFString(exec);
1690 if (UNLIKELY(scope.exception())) {
1691 JSValue exception = scope.exception();
1692 scope.clearException();
1693 return deferred->reject(exec, exception);
1694 }
1695
1696 // Here, now we consider moduleKey as the fileName.
1697 Vector<char> utf8;
1698 if (!fetchModuleFromLocalFileSystem(moduleKey, utf8))
1699 return deferred->reject(exec, createError(exec, makeString("Could not open file '", moduleKey, "'.")));
1700
1701 return deferred->resolve(exec, JSSourceCode::create(exec->vm(), makeSource(stringFromUTF(utf8), SourceOrigin { moduleKey }, moduleKey, TextPosition(), SourceProviderSourceType::Module)));
1702}
1703
1704
1705static EncodedJSValue printInternal(ExecState* exec, FILE* out)
1706{
1707 VM& vm = exec->vm();
1708 auto scope = DECLARE_THROW_SCOPE(vm);
1709
1710 if (test262AsyncTest) {
1711 JSValue value = exec->argument(0);
1712 if (value.isString() && WTF::equal(asString(value)->value(exec).impl(), "Test262:AsyncTestComplete"))
1713 test262AsyncPassed = true;
1714 return JSValue::encode(jsUndefined());
1715 }
1716
1717 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1718 if (i)
1719 if (EOF == fputc(' ', out))
1720 goto fail;
1721
1722 auto viewWithString = exec->uncheckedArgument(i).toString(exec)->viewWithUnderlyingString(*exec);
1723 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1724 if (fprintf(out, "%s", viewWithString.view.utf8().data()) < 0)
1725 goto fail;
1726 }
1727
1728 fputc('\n', out);
1729fail:
1730 fflush(out);
1731 return JSValue::encode(jsUndefined());
1732}
1733
1734EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState* exec) { return printInternal(exec, stdout); }
1735EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState* exec) { return printInternal(exec, stderr); }
1736
1737#ifndef NDEBUG
1738EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
1739{
1740 VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
1741 ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
1742 if (callerFrame)
1743 exec->vm().interpreter->dumpCallFrame(callerFrame);
1744 return JSValue::encode(jsUndefined());
1745}
1746#endif
1747
1748EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
1749{
1750 VM& vm = exec->vm();
1751 auto scope = DECLARE_THROW_SCOPE(vm);
1752 auto viewWithString = exec->argument(0).toString(exec)->viewWithUnderlyingString(*exec);
1753 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1754 fprintf(stderr, "--> %s\n", viewWithString.view.utf8().data());
1755 return JSValue::encode(jsUndefined());
1756}
1757
1758EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
1759{
1760 if (exec->argumentCount() < 1)
1761 return JSValue::encode(jsUndefined());
1762 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
1763}
1764
1765EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
1766{
1767 if (exec->argumentCount() < 1)
1768 return JSValue::encode(jsUndefined());
1769 VM& vm = exec->vm();
1770 JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(0));
1771 if (!object)
1772 return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
1773 return JSValue::encode(jsNontrivialString(exec, toString("<Butterfly: ", RawPointer(object->butterfly()), "; public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
1774}
1775
1776EncodedJSValue JSC_HOST_CALL functionSleepSeconds(ExecState* exec)
1777{
1778 VM& vm = exec->vm();
1779 auto scope = DECLARE_THROW_SCOPE(vm);
1780
1781 if (exec->argumentCount() >= 1) {
1782 Seconds seconds = Seconds(exec->argument(0).toNumber(exec));
1783 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1784 sleep(seconds);
1785 }
1786
1787 return JSValue::encode(jsUndefined());
1788}
1789
1790class FunctionJSCStackFunctor {
1791public:
1792 FunctionJSCStackFunctor(StringBuilder& trace)
1793 : m_trace(trace)
1794 {
1795 }
1796
1797 StackVisitor::Status operator()(StackVisitor& visitor) const
1798 {
1799 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
1800 return StackVisitor::Continue;
1801 }
1802
1803private:
1804 StringBuilder& m_trace;
1805};
1806
1807EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
1808{
1809 StringBuilder trace;
1810 trace.appendLiteral("--> Stack trace:\n");
1811
1812 FunctionJSCStackFunctor functor(trace);
1813 exec->iterate(functor);
1814 fprintf(stderr, "%s", trace.toString().utf8().data());
1815 return JSValue::encode(jsUndefined());
1816}
1817
1818EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
1819{
1820 JSLockHolder lock(exec);
1821 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
1822}
1823
1824EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
1825{
1826 VM& vm = exec->vm();
1827 JSLockHolder lock(vm);
1828 auto scope = DECLARE_THROW_SCOPE(vm);
1829
1830 Root* root = jsDynamicCast<Root*>(vm, exec->argument(0));
1831 if (!root)
1832 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Cannot create Element without a Root."))));
1833 return JSValue::encode(Element::create(vm, exec->lexicalGlobalObject(), root));
1834}
1835
1836EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
1837{
1838 JSLockHolder lock(exec);
1839 VM& vm = exec->vm();
1840 Root* root = jsDynamicCast<Root*>(vm, exec->argument(0));
1841 if (!root)
1842 return JSValue::encode(jsUndefined());
1843 Element* result = root->element();
1844 return JSValue::encode(result ? result : jsUndefined());
1845}
1846
1847EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
1848{
1849 JSLockHolder lock(exec);
1850 VM& vm = exec->vm();
1851 Element* element = jsDynamicCast<Element*>(vm, exec->argument(0));
1852 Root* root = jsDynamicCast<Root*>(vm, exec->argument(1));
1853 if (element && root)
1854 element->setRoot(exec->vm(), root);
1855 return JSValue::encode(jsUndefined());
1856}
1857
1858EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec)
1859{
1860 JSLockHolder lock(exec);
1861 return JSValue::encode(SimpleObject::create(exec->vm(), exec->lexicalGlobalObject()));
1862}
1863
1864EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec)
1865{
1866 VM& vm = exec->vm();
1867 JSLockHolder lock(vm);
1868 auto scope = DECLARE_THROW_SCOPE(vm);
1869
1870 SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(vm, exec->argument(0));
1871 if (UNLIKELY(!simpleObject)) {
1872 throwTypeError(exec, scope, ASCIILiteral("Invalid use of getHiddenValue test function"));
1873 return encodedJSValue();
1874 }
1875 return JSValue::encode(simpleObject->hiddenValue());
1876}
1877
1878EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec)
1879{
1880 VM& vm = exec->vm();
1881 JSLockHolder lock(vm);
1882 auto scope = DECLARE_THROW_SCOPE(vm);
1883
1884 SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(vm, exec->argument(0));
1885 if (UNLIKELY(!simpleObject)) {
1886 throwTypeError(exec, scope, ASCIILiteral("Invalid use of setHiddenValue test function"));
1887 return encodedJSValue();
1888 }
1889 JSValue value = exec->argument(1);
1890 simpleObject->setHiddenValue(exec->vm(), value);
1891 return JSValue::encode(jsUndefined());
1892}
1893
1894EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
1895{
1896 JSLockHolder lock(exec);
1897 JSValue target = exec->argument(0);
1898 if (!target.isObject())
1899 return JSValue::encode(jsUndefined());
1900 JSObject* jsTarget = asObject(target.asCell());
1901 Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->getPrototypeDirect(), ImpureProxyType);
1902 JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
1903 return JSValue::encode(proxy);
1904}
1905
1906EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
1907{
1908 JSLockHolder lock(exec);
1909 RuntimeArray* array = RuntimeArray::create(exec);
1910 return JSValue::encode(array);
1911}
1912
1913EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
1914{
1915 JSLockHolder lock(exec);
1916 JSValue target = exec->argument(0);
1917 JSObject* delegate = nullptr;
1918 if (target.isObject())
1919 delegate = asObject(target.asCell());
1920 Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1921 ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
1922 return JSValue::encode(result);
1923}
1924
1925EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec)
1926{
1927 JSLockHolder lock(exec);
1928 Structure* structure = CustomGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1929 CustomGetter* result = CustomGetter::create(exec->vm(), structure);
1930 return JSValue::encode(result);
1931}
1932
1933EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec)
1934{
1935 JSLockHolder lock(exec);
1936 Structure* structure = DOMJITNode::createStructure(exec->vm(), exec->lexicalGlobalObject(), DOMJITGetter::create(exec->vm(), DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull())));
1937 DOMJITNode* result = DOMJITNode::create(exec->vm(), structure);
1938 return JSValue::encode(result);
1939}
1940
1941EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec)
1942{
1943 JSLockHolder lock(exec);
1944 Structure* structure = DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1945 DOMJITGetter* result = DOMJITGetter::create(exec->vm(), structure);
1946 return JSValue::encode(result);
1947}
1948
1949EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec)
1950{
1951 JSLockHolder lock(exec);
1952 Structure* structure = DOMJITGetterComplex::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1953 DOMJITGetterComplex* result = DOMJITGetterComplex::create(exec->vm(), exec->lexicalGlobalObject(), structure);
1954 return JSValue::encode(result);
1955}
1956
1957EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState* exec)
1958{
1959 JSLockHolder lock(exec);
1960 Structure* structure = DOMJITFunctionObject::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1961 DOMJITFunctionObject* result = DOMJITFunctionObject::create(exec->vm(), exec->lexicalGlobalObject(), structure);
1962 return JSValue::encode(result);
1963}
1964
1965EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
1966{
1967 VM& vm = exec->vm();
1968 JSLockHolder lock(vm);
1969 auto scope = DECLARE_THROW_SCOPE(vm);
1970
1971 JSValue base = exec->argument(0);
1972 if (!base.isObject())
1973 return JSValue::encode(jsUndefined());
1974 JSValue delegate = exec->argument(1);
1975 if (!delegate.isObject())
1976 return JSValue::encode(jsUndefined());
1977 ImpureGetter* impureGetter = jsDynamicCast<ImpureGetter*>(vm, asObject(base.asCell()));
1978 if (UNLIKELY(!impureGetter)) {
1979 throwTypeError(exec, scope, ASCIILiteral("argument is not an ImpureGetter"));
1980 return encodedJSValue();
1981 }
1982 impureGetter->setDelegate(vm, asObject(delegate.asCell()));
1983 return JSValue::encode(jsUndefined());
1984}
1985
1986EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
1987{
1988 JSLockHolder lock(exec);
1989 exec->heap()->collectAllGarbage();
1990 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1991}
1992
1993EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
1994{
1995 JSLockHolder lock(exec);
1996 exec->heap()->collectSync(CollectionScope::Full);
1997 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1998}
1999
2000EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
2001{
2002 JSLockHolder lock(exec);
2003 exec->heap()->collectSync(CollectionScope::Eden);
2004 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastEdenCollection()));
2005}
2006
2007EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*)
2008{
2009 // It's best for this to be the first thing called in the
2010 // JS program so the option is set to true before we JIT.
2011 Options::forceGCSlowPaths() = true;
2012 return JSValue::encode(jsUndefined());
2013}
2014
2015EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
2016{
2017 JSLockHolder lock(exec);
2018 return JSValue::encode(jsNumber(exec->heap()->size()));
2019}
2020
2021// This function is not generally very helpful in 64-bit code as the tag and payload
2022// share a register. But in 32-bit JITed code the tag may not be checked if an
2023// optimization removes type checking requirements, such as in ===.
2024EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState* exec)
2025{
2026 JSValue value = exec->argument(0);
2027 if (!value.isCell())
2028 return JSValue::encode(jsUndefined());
2029 // Need to cast to uint64_t so bitwise_cast will play along.
2030 uint64_t asNumber = reinterpret_cast<uint64_t>(value.asCell());
2031 EncodedJSValue returnValue = JSValue::encode(jsNumber(bitwise_cast<double>(asNumber)));
2032 return returnValue;
2033}
2034
2035static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState* exec)
2036{
2037 JSValue value = exec->argument(0);
2038 if (!value.isObject())
2039 return JSValue::encode(jsUndefined());
2040
2041 JSValue property = exec->argument(1);
2042 if (!property.isString())
2043 return JSValue::encode(jsUndefined());
2044
2045 PropertySlot slot(value, PropertySlot::InternalMethodType::VMInquiry);
2046 value.getPropertySlot(exec, asString(property)->toIdentifier(exec), slot);
2047
2048 JSValue result;
2049 if (slot.isCacheableGetter())
2050 result = slot.getterSetter();
2051 else
2052 result = jsNull();
2053
2054 return JSValue::encode(result);
2055}
2056
2057EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
2058{
2059 // We need this function for compatibility with the Mozilla JS tests but for now
2060 // we don't actually do any version-specific handling
2061 return JSValue::encode(jsUndefined());
2062}
2063
2064EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
2065{
2066 VM& vm = exec->vm();
2067 auto scope = DECLARE_THROW_SCOPE(vm);
2068
2069 String fileName = exec->argument(0).toWTFString(exec);
2070 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2071 Vector<char> script;
2072 if (!fetchScriptFromLocalFileSystem(fileName, script))
2073 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2074
2075 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
2076
2077 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
2078 for (unsigned i = 1; i < exec->argumentCount(); ++i)
2079 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
2080 globalObject->putDirect(
2081 vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
2082
2083 NakedPtr<Exception> exception;
2084 StopWatch stopWatch;
2085 stopWatch.start();
2086 evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), exception);
2087 stopWatch.stop();
2088
2089 if (exception) {
2090 throwException(globalObject->globalExec(), scope, exception);
2091 return JSValue::encode(jsUndefined());
2092 }
2093
2094 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2095}
2096
2097EncodedJSValue JSC_HOST_CALL functionRunString(ExecState* exec)
2098{
2099 VM& vm = exec->vm();
2100 auto scope = DECLARE_THROW_SCOPE(vm);
2101
2102 String source = exec->argument(0).toWTFString(exec);
2103 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2104
2105 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
2106
2107 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
2108 for (unsigned i = 1; i < exec->argumentCount(); ++i)
2109 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
2110 globalObject->putDirect(
2111 vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
2112
2113 NakedPtr<Exception> exception;
2114 evaluate(globalObject->globalExec(), makeSource(source, exec->callerSourceOrigin()), JSValue(), exception);
2115
2116 if (exception) {
2117 scope.throwException(globalObject->globalExec(), exception);
2118 return JSValue::encode(jsUndefined());
2119 }
2120
2121 return JSValue::encode(globalObject);
2122}
2123
2124EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
2125{
2126 VM& vm = exec->vm();
2127 auto scope = DECLARE_THROW_SCOPE(vm);
2128
2129 String fileName = exec->argument(0).toWTFString(exec);
2130 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2131 Vector<char> script;
2132 if (!fetchScriptFromLocalFileSystem(fileName, script))
2133 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2134
2135 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2136
2137 NakedPtr<Exception> evaluationException;
2138 JSValue result = evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
2139 if (evaluationException)
2140 throwException(exec, scope, evaluationException);
2141 return JSValue::encode(result);
2142}
2143
2144EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState* exec)
2145{
2146 VM& vm = exec->vm();
2147 auto scope = DECLARE_THROW_SCOPE(vm);
2148
2149 String sourceCode = exec->argument(0).toWTFString(exec);
2150 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2151 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2152
2153 NakedPtr<Exception> evaluationException;
2154 JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
2155 if (evaluationException)
2156 throwException(exec, scope, evaluationException);
2157 return JSValue::encode(result);
2158}
2159
2160EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
2161{
2162 VM& vm = exec->vm();
2163 auto scope = DECLARE_THROW_SCOPE(vm);
2164
2165 String fileName = exec->argument(0).toWTFString(exec);
2166 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2167
2168 bool isBinary = false;
2169 if (exec->argumentCount() > 1) {
2170 String type = exec->argument(1).toWTFString(exec);
2171 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2172 if (type != "binary")
2173 return throwVMError(exec, scope, "Expected 'binary' as second argument.");
2174 isBinary = true;
2175 }
2176
2177 Vector<char> content;
2178 if (!fillBufferWithContentsOfFile(fileName, content))
2179 return throwVMError(exec, scope, "Could not open file.");
2180
2181 if (!isBinary)
2182 return JSValue::encode(jsString(exec, stringFromUTF(content)));
2183
2184 Structure* structure = exec->lexicalGlobalObject()->typedArrayStructure(TypeUint8);
2185 auto length = content.size();
2186 JSObject* result = createUint8TypedArray(exec, structure, ArrayBuffer::createFromBytes(content.releaseBuffer().leakPtr(), length, [] (void* p) { fastFree(p); }), 0, length);
2187 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2188
2189 return JSValue::encode(result);
2190}
2191
2192EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
2193{
2194 VM& vm = exec->vm();
2195 auto scope = DECLARE_THROW_SCOPE(vm);
2196
2197 String fileName = exec->argument(0).toWTFString(exec);
2198 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2199 Vector<char> script;
2200 if (!fetchScriptFromLocalFileSystem(fileName, script))
2201 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2202
2203 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2204
2205 StopWatch stopWatch;
2206 stopWatch.start();
2207
2208 JSValue syntaxException;
2209 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), &syntaxException);
2210 stopWatch.stop();
2211
2212 if (!validSyntax)
2213 throwException(exec, scope, syntaxException);
2214 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2215}
2216
2217#if ENABLE(SAMPLING_FLAGS)
2218EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
2219{
2220 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2221 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
2222 if ((flag >= 1) && (flag <= 32))
2223 SamplingFlags::setFlag(flag);
2224 }
2225 return JSValue::encode(jsNull());
2226}
2227
2228EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
2229{
2230 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2231 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
2232 if ((flag >= 1) && (flag <= 32))
2233 SamplingFlags::clearFlag(flag);
2234 }
2235 return JSValue::encode(jsNull());
2236}
2237#endif
2238
2239EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState* exec)
2240{
2241 return JSValue::encode(exec->vm().shadowChicken().functionsOnStack(exec));
2242}
2243
2244EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState* exec)
2245{
2246 exec->vm().setGlobalConstRedeclarationShouldThrow(false);
2247 return JSValue::encode(jsUndefined());
2248}
2249
2250EncodedJSValue JSC_HOST_CALL functionGetRandomSeed(ExecState* exec)
2251{
2252 return JSValue::encode(jsNumber(exec->lexicalGlobalObject()->weakRandom().seed()));
2253}
2254
2255EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState* exec)
2256{
2257 VM& vm = exec->vm();
2258 auto scope = DECLARE_THROW_SCOPE(vm);
2259
2260 unsigned seed = exec->argument(0).toUInt32(exec);
2261 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2262 exec->lexicalGlobalObject()->weakRandom().setSeed(seed);
2263 return JSValue::encode(jsUndefined());
2264}
2265
2266EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState* exec)
2267{
2268 JSValue argument = exec->argument(0);
2269 if (!argument.isString())
2270 return JSValue::encode(jsBoolean(false));
2271 const StringImpl* impl = asString(argument)->tryGetValueImpl();
2272 return JSValue::encode(jsBoolean(!impl));
2273}
2274
2275EncodedJSValue JSC_HOST_CALL functionCallerSourceOrigin(ExecState* state)
2276{
2277 SourceOrigin sourceOrigin = state->callerSourceOrigin();
2278 if (sourceOrigin.isNull())
2279 return JSValue::encode(jsNull());
2280 return JSValue::encode(jsString(state, sourceOrigin.string()));
2281}
2282
2283EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState* exec)
2284{
2285 JSValue value = exec->argument(0);
2286 RELEASE_ASSERT(value.isObject());
2287 JSGlobalObject* globalObject = jsCast<JSObject*>(value)->globalObject();
2288 RELEASE_ASSERT(globalObject);
2289 return JSValue::encode(globalObject);
2290}
2291
2292EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
2293{
2294 Vector<char, 256> line;
2295 int c;
2296 while ((c = getchar()) != EOF) {
2297 // FIXME: Should we also break on \r?
2298 if (c == '\n')
2299 break;
2300 line.append(c);
2301 }
2302 line.append('\0');
2303 return JSValue::encode(jsString(exec, line.data()));
2304}
2305
2306EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
2307{
2308 return JSValue::encode(jsNumber(currentTime()));
2309}
2310
2311EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
2312{
2313 return JSValue::encode(setNeverInline(exec));
2314}
2315
2316EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState* exec)
2317{
2318 return JSValue::encode(setNeverOptimize(exec));
2319}
2320
2321EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState* exec)
2322{
2323 VM& vm = exec->vm();
2324 if (JSFunction* function = jsDynamicCast<JSFunction*>(vm, exec->argument(0))) {
2325 FunctionExecutable* executable = function->jsExecutable();
2326 executable->setNeverFTLOptimize(true);
2327 }
2328
2329 return JSValue::encode(jsUndefined());
2330}
2331
2332EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState* exec)
2333{
2334 return JSValue::encode(setCannotUseOSRExitFuzzing(exec));
2335}
2336
2337EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
2338{
2339 return JSValue::encode(optimizeNextInvocation(exec));
2340}
2341
2342EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
2343{
2344 return JSValue::encode(numberOfDFGCompiles(exec));
2345}
2346
2347Message::Message(ArrayBufferContents&& contents, int32_t index)
2348 : m_contents(WTFMove(contents))
2349 , m_index(index)
2350{
2351}
2352
2353Message::~Message()
2354{
2355}
2356
2357Worker::Worker(Workers& workers)
2358 : m_workers(workers)
2359{
2360 auto locker = holdLock(m_workers.m_lock);
2361 m_workers.m_workers.append(this);
2362
2363 *currentWorker() = this;
2364}
2365
2366Worker::~Worker()
2367{
2368 auto locker = holdLock(m_workers.m_lock);
2369 RELEASE_ASSERT(isOnList());
2370 remove();
2371}
2372
2373void Worker::enqueue(const AbstractLocker&, RefPtr<Message> message)
2374{
2375 m_messages.append(message);
2376}
2377
2378RefPtr<Message> Worker::dequeue()
2379{
2380 auto locker = holdLock(m_workers.m_lock);
2381 while (m_messages.isEmpty())
2382 m_workers.m_condition.wait(m_workers.m_lock);
2383 return m_messages.takeFirst();
2384}
2385
2386Worker& Worker::current()
2387{
2388 return **currentWorker();
2389}
2390
2391ThreadSpecific<Worker*>& Worker::currentWorker()
2392{
2393 static ThreadSpecific<Worker*>* result;
2394 static std::once_flag flag;
2395 std::call_once(
2396 flag,
2397 [] () {
2398 result = new ThreadSpecific<Worker*>();
2399 });
2400 return *result;
2401}
2402
2403Workers::Workers()
2404{
2405}
2406
2407Workers::~Workers()
2408{
2409 UNREACHABLE_FOR_PLATFORM();
2410}
2411
2412template<typename Func>
2413void Workers::broadcast(const Func& func)
2414{
2415 auto locker = holdLock(m_lock);
2416 for (Worker* worker = m_workers.begin(); worker != m_workers.end(); worker = worker->next()) {
2417 if (worker != &Worker::current())
2418 func(locker, *worker);
2419 }
2420 m_condition.notifyAll();
2421}
2422
2423void Workers::report(String string)
2424{
2425 auto locker = holdLock(m_lock);
2426 m_reports.append(string.isolatedCopy());
2427 m_condition.notifyAll();
2428}
2429
2430String Workers::tryGetReport()
2431{
2432 auto locker = holdLock(m_lock);
2433 if (m_reports.isEmpty())
2434 return String();
2435 return m_reports.takeFirst();
2436}
2437
2438String Workers::getReport()
2439{
2440 auto locker = holdLock(m_lock);
2441 while (m_reports.isEmpty())
2442 m_condition.wait(m_lock);
2443 return m_reports.takeFirst();
2444}
2445
2446Workers& Workers::singleton()
2447{
2448 static Workers* result;
2449 static std::once_flag flag;
2450 std::call_once(
2451 flag,
2452 [] {
2453 result = new Workers();
2454 });
2455 return *result;
2456}
2457
2458EncodedJSValue JSC_HOST_CALL functionDollarCreateRealm(ExecState* exec)
2459{
2460 VM& vm = exec->vm();
2461 GlobalObject* result = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
2462 return JSValue::encode(result->getDirect(vm, Identifier::fromString(exec, "$")));
2463}
2464
2465EncodedJSValue JSC_HOST_CALL functionDollarDetachArrayBuffer(ExecState* exec)
2466{
2467 return functionTransferArrayBuffer(exec);
2468}
2469
2470EncodedJSValue JSC_HOST_CALL functionDollarEvalScript(ExecState* exec)
2471{
2472 VM& vm = exec->vm();
2473 auto scope = DECLARE_THROW_SCOPE(vm);
2474
2475 String sourceCode = exec->argument(0).toWTFString(exec);
2476 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2477
2478 GlobalObject* globalObject = jsDynamicCast<GlobalObject*>(vm,
2479 exec->thisValue().get(exec, Identifier::fromString(exec, "global")));
2480 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2481 if (!globalObject)
2482 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected global to point to a global object"))));
2483
2484 NakedPtr<Exception> evaluationException;
2485 JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
2486 if (evaluationException)
2487 throwException(exec, scope, evaluationException);
2488 return JSValue::encode(result);
2489}
2490
2491EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState* exec)
2492{
2493 VM& vm = exec->vm();
2494 auto scope = DECLARE_THROW_SCOPE(vm);
2495
2496 String sourceCode = exec->argument(0).toWTFString(exec).isolatedCopy();
2497 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2498
2499 Lock didStartLock;
2500 Condition didStartCondition;
2501 bool didStart = false;
2502
2503 ThreadIdentifier thread = createThread(
2504 "JSC Agent",
2505 [sourceCode, &didStartLock, &didStartCondition, &didStart] () {
2506 CommandLine commandLine(0, nullptr);
2507 commandLine.m_interactive = false;
2508 runJSC(
2509 commandLine,
2510 [&] (VM&, GlobalObject* globalObject) {
2511 // Notify the thread that started us that we have registered a worker.
2512 {
2513 auto locker = holdLock(didStartLock);
2514 didStart = true;
2515 didStartCondition.notifyOne();
2516 }
2517
2518 NakedPtr<Exception> evaluationException;
2519 bool success = true;
2520 JSValue result;
2521 result = evaluate(globalObject->globalExec(), makeSource(sourceCode, SourceOrigin(ASCIILiteral("worker"))), JSValue(), evaluationException);
2522 if (evaluationException)
2523 result = evaluationException->value();
2524 checkException(globalObject, true, evaluationException, result, String(), false, false, success);
2525 if (!success)
2526 exit(1);
2527 return success;
2528 });
2529 });
2530 detachThread(thread);
2531
2532 {
2533 auto locker = holdLock(didStartLock);
2534 while (!didStart)
2535 didStartCondition.wait(didStartLock);
2536 }
2537
2538 return JSValue::encode(jsUndefined());
2539}
2540
2541EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState* exec)
2542{
2543 VM& vm = exec->vm();
2544 auto scope = DECLARE_THROW_SCOPE(vm);
2545
2546 JSValue callback = exec->argument(0);
2547 CallData callData;
2548 CallType callType = getCallData(callback, callData);
2549 if (callType == CallType::None)
2550 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected callback"))));
2551
2552 RefPtr<Message> message;
2553 {
2554 ReleaseHeapAccessScope releaseAccess(vm.heap);
2555 message = Worker::current().dequeue();
2556 }
2557
2558 RefPtr<ArrayBuffer> nativeBuffer = ArrayBuffer::create(message->releaseContents());
2559 JSArrayBuffer* jsBuffer = JSArrayBuffer::create(vm, exec->lexicalGlobalObject()->arrayBufferStructure(nativeBuffer->sharingMode()), nativeBuffer);
2560
2561 MarkedArgumentBuffer args;
2562 args.append(jsBuffer);
2563 args.append(jsNumber(message->index()));
2564 return JSValue::encode(call(exec, callback, callType, callData, jsNull(), args));
2565}
2566
2567EncodedJSValue JSC_HOST_CALL functionDollarAgentReport(ExecState* exec)
2568{
2569 VM& vm = exec->vm();
2570 auto scope = DECLARE_THROW_SCOPE(vm);
2571
2572 String report = exec->argument(0).toWTFString(exec);
2573 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2574
2575 Workers::singleton().report(report);
2576
2577 return JSValue::encode(jsUndefined());
2578}
2579
2580EncodedJSValue JSC_HOST_CALL functionDollarAgentSleep(ExecState* exec)
2581{
2582 VM& vm = exec->vm();
2583 auto scope = DECLARE_THROW_SCOPE(vm);
2584
2585 if (exec->argumentCount() >= 1) {
2586 Seconds seconds = Seconds::fromMilliseconds(exec->argument(0).toNumber(exec));
2587 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2588 sleep(seconds);
2589 }
2590 return JSValue::encode(jsUndefined());
2591}
2592
2593EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState* exec)
2594{
2595 VM& vm = exec->vm();
2596 auto scope = DECLARE_THROW_SCOPE(vm);
2597
2598 JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(vm, exec->argument(0));
2599 if (!jsBuffer || !jsBuffer->isShared())
2600 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected SharedArrayBuffer"))));
2601
2602 int32_t index = exec->argument(1).toInt32(exec);
2603 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2604
2605 Workers::singleton().broadcast(
2606 [&] (const AbstractLocker& locker, Worker& worker) {
2607 ArrayBuffer* nativeBuffer = jsBuffer->impl();
2608 ArrayBufferContents contents;
2609 nativeBuffer->transferTo(vm, contents); // "transferTo" means "share" if the buffer is shared.
2610 RefPtr<Message> message = adoptRef(new Message(WTFMove(contents), index));
2611 worker.enqueue(locker, message);
2612 });
2613
2614 return JSValue::encode(jsUndefined());
2615}
2616
2617EncodedJSValue JSC_HOST_CALL functionDollarAgentGetReport(ExecState* exec)
2618{
2619 VM& vm = exec->vm();
2620
2621 String string = Workers::singleton().tryGetReport();
2622 if (!string)
2623 return JSValue::encode(jsNull());
2624
2625 return JSValue::encode(jsString(&vm, string));
2626}
2627
2628EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*)
2629{
2630 return JSValue::encode(jsUndefined());
2631}
2632
2633EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState* exec)
2634{
2635 VM& vm = exec->vm();
2636
2637 String string;
2638 {
2639 ReleaseHeapAccessScope releaseAccess(vm.heap);
2640 string = Workers::singleton().getReport();
2641 }
2642 if (!string)
2643 return JSValue::encode(jsNull());
2644
2645 return JSValue::encode(jsString(&vm, string));
2646}
2647
2648EncodedJSValue JSC_HOST_CALL functionHeapCapacity(ExecState* exec)
2649{
2650 VM& vm = exec->vm();
2651 return JSValue::encode(jsNumber(vm.heap.capacity()));
2652}
2653
2654template<typename ValueType>
2655typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, Identifier, ValueType) { }
2656
2657template<typename ValueType>
2658typename std::enable_if<std::is_fundamental<ValueType>::value>::type addOption(VM& vm, JSObject* optionsObject, Identifier identifier, ValueType value)
2659{
2660 optionsObject->putDirect(vm, identifier, JSValue(value));
2661}
2662
2663EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState* exec)
2664{
2665 JSObject* optionsObject = constructEmptyObject(exec);
2666#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
2667 addOption(exec->vm(), optionsObject, Identifier::fromString(exec, #name_), Options::name_());
2668 JSC_OPTIONS(FOR_EACH_OPTION)
2669#undef FOR_EACH_OPTION
2670 return JSValue::encode(optionsObject);
2671}
2672
2673EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
2674{
2675 if (exec->argumentCount() < 1)
2676 return JSValue::encode(jsUndefined());
2677
2678 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
2679 if (!block)
2680 return JSValue::encode(jsNumber(0));
2681
2682 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
2683}
2684
2685EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
2686{
2687 VM& vm = exec->vm();
2688 auto scope = DECLARE_THROW_SCOPE(vm);
2689
2690 if (exec->argumentCount() < 1)
2691 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Not enough arguments"))));
2692
2693 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(vm, exec->argument(0));
2694 if (!buffer)
2695 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected an array buffer"))));
2696
2697 ArrayBufferContents dummyContents;
2698 buffer->impl()->transferTo(vm, dummyContents);
2699
2700 return JSValue::encode(jsUndefined());
2701}
2702
2703EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState* exec)
2704{
2705 exec->vm().setFailNextNewCodeBlock();
2706 return JSValue::encode(jsUndefined());
2707}
2708
2709EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
2710{
2711 jscExit(EXIT_SUCCESS);
2712
2713#if COMPILER(MSVC)
2714 // Without this, Visual Studio will complain that this method does not return a value.
2715 return JSValue::encode(jsUndefined());
2716#endif
2717}
2718
2719EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*)
2720{
2721 CRASH();
2722}
2723
2724EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
2725EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
2726
2727EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
2728EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
2729EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
2730{
2731 for (size_t i = 0; i < exec->argumentCount(); ++i) {
2732 if (!exec->argument(i).isInt32())
2733 return JSValue::encode(jsBoolean(false));
2734 }
2735 return JSValue::encode(jsBoolean(true));
2736}
2737
2738EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
2739
2740EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
2741{
2742 return JSValue::encode(jsNumber(42));
2743}
2744
2745EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
2746{
2747 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
2748}
2749
2750EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
2751{
2752 JSValue value = exec->argument(0);
2753 if (value.isObject())
2754 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
2755 return JSValue::encode(jsBoolean(false));
2756}
2757
2758EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
2759{
2760 exec->vm().dumpTypeProfilerData();
2761 return JSValue::encode(jsUndefined());
2762}
2763
2764EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
2765{
2766 VM& vm = exec->vm();
2767 RELEASE_ASSERT(exec->vm().typeProfiler());
2768 vm.typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
2769
2770 JSValue functionValue = exec->argument(0);
2771 RELEASE_ASSERT(functionValue.isFunction());
2772 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2773
2774 RELEASE_ASSERT(exec->argument(1).isString());
2775 String substring = asString(exec->argument(1))->value(exec);
2776 String sourceCodeText = executable->source().view().toString();
2777 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
2778
2779 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
2780 return JSValue::encode(JSONParse(exec, jsonString));
2781}
2782
2783EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
2784{
2785 VM& vm = exec->vm();
2786 RELEASE_ASSERT(exec->vm().typeProfiler());
2787 vm.typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
2788
2789 JSValue functionValue = exec->argument(0);
2790 RELEASE_ASSERT(functionValue.isFunction());
2791 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2792
2793 unsigned offset = executable->typeProfilingStartOffset();
2794 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
2795 return JSValue::encode(JSONParse(exec, jsonString));
2796}
2797
2798EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
2799{
2800 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
2801 exec->vm().controlFlowProfiler()->dumpData();
2802 return JSValue::encode(jsUndefined());
2803}
2804
2805EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
2806{
2807 VM& vm = exec->vm();
2808 RELEASE_ASSERT(vm.controlFlowProfiler());
2809
2810 JSValue functionValue = exec->argument(0);
2811 RELEASE_ASSERT(functionValue.isFunction());
2812 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2813
2814 RELEASE_ASSERT(exec->argument(1).isString());
2815 String substring = asString(exec->argument(1))->value(exec);
2816 String sourceCodeText = executable->source().view().toString();
2817 RELEASE_ASSERT(sourceCodeText.contains(substring));
2818 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
2819
2820 bool hasExecuted = vm.controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), vm);
2821 return JSValue::encode(jsBoolean(hasExecuted));
2822}
2823
2824EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec)
2825{
2826 VM& vm = exec->vm();
2827 RELEASE_ASSERT(vm.controlFlowProfiler());
2828
2829 JSValue functionValue = exec->argument(0);
2830 RELEASE_ASSERT(functionValue.isFunction());
2831 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable();
2832
2833 RELEASE_ASSERT(exec->argument(1).isString());
2834 String substring = asString(exec->argument(1))->value(exec);
2835 String sourceCodeText = executable->source().view().toString();
2836 RELEASE_ASSERT(sourceCodeText.contains(substring));
2837 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
2838
2839 size_t executionCount = vm.controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), exec->vm());
2840 return JSValue::encode(JSValue(executionCount));
2841}
2842
2843EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
2844{
2845 Options::useExceptionFuzz() = true;
2846 return JSValue::encode(jsUndefined());
2847}
2848
2849EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState* exec)
2850{
2851 exec->vm().drainMicrotasks();
2852 return JSValue::encode(jsUndefined());
2853}
2854
2855EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*)
2856{
2857#if USE(JSVALUE64)
2858 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
2859#else
2860 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
2861#endif
2862}
2863
2864EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
2865{
2866 VM& vm = exec->vm();
2867 auto scope = DECLARE_THROW_SCOPE(vm);
2868
2869 String fileName = exec->argument(0).toWTFString(exec);
2870 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2871 Vector<char> script;
2872 if (!fetchScriptFromLocalFileSystem(fileName, script))
2873 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2874
2875 JSInternalPromise* promise = loadAndEvaluateModule(exec, fileName);
2876 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2877
2878 JSValue error;
2879 JSFunction* errorHandler = JSNativeStdFunction::create(vm, exec->lexicalGlobalObject(), 1, String(), [&](ExecState* exec) {
2880 error = exec->argument(0);
2881 return JSValue::encode(jsUndefined());
2882 });
2883
2884 promise->then(exec, nullptr, errorHandler);
2885 vm.drainMicrotasks();
2886 if (error)
2887 return JSValue::encode(throwException(exec, scope, error));
2888 return JSValue::encode(jsUndefined());
2889}
2890
2891EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState* exec)
2892{
2893 VM& vm = exec->vm();
2894 auto scope = DECLARE_THROW_SCOPE(vm);
2895
2896 if (exec->argumentCount() < 1 || !exec->argument(0).isString())
2897 return JSValue::encode(jsUndefined());
2898
2899 String functionText = asString(exec->argument(0))->value(exec);
2900 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2901
2902 const SourceCode& source = makeSource(functionText, { });
2903 JSFunction* func = JSFunction::createBuiltinFunction(vm, createBuiltinExecutable(vm, source, Identifier::fromString(&vm, "foo"), ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, source), exec->lexicalGlobalObject());
2904
2905 return JSValue::encode(func);
2906}
2907
2908EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
2909{
2910 VM& vm = exec->vm();
2911 return JSValue::encode(GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>()));
2912}
2913
2914EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState* exec)
2915{
2916 VM& vm = exec->vm();
2917 auto scope = DECLARE_THROW_SCOPE(vm);
2918
2919 String source = exec->argument(0).toWTFString(exec);
2920 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2921
2922 StopWatch stopWatch;
2923 stopWatch.start();
2924
2925 ParserError error;
2926 bool validSyntax = checkModuleSyntax(exec, makeSource(source, { }, String(), TextPosition(), SourceProviderSourceType::Module), error);
2927 stopWatch.stop();
2928
2929 if (!validSyntax)
2930 throwException(exec, scope, jsNontrivialString(exec, toString("SyntaxError: ", error.message(), ":", error.line())));
2931 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2932}
2933
2934EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*)
2935{
2936#if ENABLE(SAMPLING_PROFILER)
2937 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
2938#else
2939 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
2940#endif
2941}
2942
2943EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState* exec)
2944{
2945 VM& vm = exec->vm();
2946 JSLockHolder lock(vm);
2947 auto scope = DECLARE_THROW_SCOPE(vm);
2948
2949 HeapSnapshotBuilder snapshotBuilder(exec->vm().ensureHeapProfiler());
2950 snapshotBuilder.buildSnapshot();
2951
2952 String jsonString = snapshotBuilder.json();
2953 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
2954 RELEASE_ASSERT(!scope.exception());
2955 return result;
2956}
2957
2958EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*)
2959{
2960 resetSuperSamplerState();
2961 return JSValue::encode(jsUndefined());
2962}
2963
2964EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState* exec)
2965{
2966 VM& vm = exec->vm();
2967 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2968 if (JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(0)))
2969 object->ensureArrayStorage(exec->vm());
2970 }
2971 return JSValue::encode(jsUndefined());
2972}
2973
2974#if ENABLE(SAMPLING_PROFILER)
2975EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState* exec)
2976{
2977 SamplingProfiler& samplingProfiler = exec->vm().ensureSamplingProfiler(WTF::Stopwatch::create());
2978 samplingProfiler.noticeCurrentThreadAsJSCExecutionThread();
2979 samplingProfiler.start();
2980 return JSValue::encode(jsUndefined());
2981}
2982
2983EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState* exec)
2984{
2985 VM& vm = exec->vm();
2986 auto scope = DECLARE_THROW_SCOPE(vm);
2987
2988 if (!vm.samplingProfiler())
2989 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Sampling profiler was never started"))));
2990
2991 String jsonString = vm.samplingProfiler()->stackTracesAsJSON();
2992 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
2993 RELEASE_ASSERT(!scope.exception());
2994 return result;
2995}
2996#endif // ENABLE(SAMPLING_PROFILER)
2997
2998EncodedJSValue JSC_HOST_CALL functionMaxArguments(ExecState*)
2999{
3000 return JSValue::encode(jsNumber(JSC::maxArguments));
3001}
3002
3003#if ENABLE(WEBASSEMBLY)
3004
3005static CString valueWithTypeOfWasmValue(ExecState* exec, VM& vm, JSValue value, JSValue wasmValue)
3006{
3007 JSString* type = asString(wasmValue.get(exec, makeIdentifier(vm, "type")));
3008
3009 const String& typeString = type->value(exec);
3010 if (typeString == "i64" || typeString == "i32")
3011 return toCString(typeString, " ", RawPointer(bitwise_cast<void*>(value)));
3012 if (typeString == "f32")
3013 return toCString(typeString, " hex: ", RawPointer(bitwise_cast<void*>(value)), ", float: ", bitwise_cast<float>(static_cast<uint32_t>(JSValue::encode(value))));
3014 return toCString(typeString, " hex: ", RawPointer(bitwise_cast<void*>(value)), ", double: ", bitwise_cast<double>(value));
3015}
3016
3017static JSValue box(ExecState* exec, VM& vm, JSValue wasmValue)
3018{
3019
3020 JSString* type = asString(wasmValue.get(exec, makeIdentifier(vm, "type")));
3021 JSValue value = wasmValue.get(exec, makeIdentifier(vm, "value"));
3022
3023 auto unboxString = [&] (const char* hexFormat, const char* decFormat, auto& result) {
3024 if (!value.isString())
3025 return false;
3026
3027 const char* str = toCString(asString(value)->value(exec)).data();
3028 int scanResult;
3029 int length = std::strlen(str);
3030 if ((length > 2 && (str[0] == '0' && str[1] == 'x'))
3031 || (length > 3 && (str[0] == '-' && str[1] == '0' && str[2] == 'x')))
3032#if COMPILER(CLANG)
3033#pragma clang diagnostic push
3034#pragma clang diagnostic ignored "-Wformat-nonliteral"
3035#endif
3036 scanResult = sscanf(str, hexFormat, &result);
3037 else
3038 scanResult = sscanf(str, decFormat, &result);
3039#if COMPILER(CLANG)
3040#pragma clang diagnostic pop
3041#endif
3042 RELEASE_ASSERT(scanResult != EOF);
3043 return true;
3044 };
3045
3046 const String& typeString = type->value(exec);
3047 if (typeString == "i64") {
3048 int64_t result;
3049 if (!unboxString("%llx", "%lld", result))
3050 CRASH();
3051 return JSValue::decode(result);
3052 }
3053
3054 if (typeString == "i32") {
3055 int32_t result;
3056 if (!unboxString("%x", "%d", result))
3057 result = value.asInt32();
3058 return JSValue::decode(static_cast<uint32_t>(result));
3059 }
3060
3061 if (typeString == "f32") {
3062 float result;
3063 if (!unboxString("%a", "%f", result))
3064 result = value.toFloat(exec);
3065 return JSValue::decode(bitwise_cast<uint32_t>(result));
3066 }
3067
3068 RELEASE_ASSERT(typeString == "f64");
3069 double result;
3070 if (!unboxString("%la", "%lf", result))
3071 result = value.asNumber();
3072 return JSValue::decode(bitwise_cast<uint64_t>(result));
3073}
3074
3075static JSValue callWasmFunction(VM* vm, JSGlobalObject* globalObject, JSWebAssemblyCallee* wasmCallee, Vector<JSValue>& boxedArgs)
3076{
3077 JSValue firstArgument;
3078 int argCount = 1;
3079 JSValue* remainingArgs = nullptr;
3080 if (boxedArgs.size()) {
3081 remainingArgs = boxedArgs.data();
3082 firstArgument = *remainingArgs;
3083 remainingArgs++;
3084 argCount = boxedArgs.size();
3085 }
3086
3087 ProtoCallFrame protoCallFrame;
3088 protoCallFrame.init(nullptr, globalObject->globalExec()->jsCallee(), firstArgument, argCount, remainingArgs);
3089
3090 return JSValue::decode(vmEntryToWasm(wasmCallee->entrypoint(), vm, &protoCallFrame));
3091}
3092
3093// testWasmModule(JSArrayBufferView source, number functionCount, ...[[WasmValue, [WasmValue]]]) where the ith copy of [[result, [args]]] is a list
3094// 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.
3095static EncodedJSValue JSC_HOST_CALL functionTestWasmModuleFunctions(ExecState* exec)
3096{
3097 VM& vm = exec->vm();
3098 auto scope = DECLARE_THROW_SCOPE(vm);
3099
3100 if (!Options::useWebAssembly())
3101 return throwVMTypeError(exec, scope, ASCIILiteral("testWasmModule should only be called if the useWebAssembly option is set"));
3102
3103 JSArrayBufferView* source = jsCast<JSArrayBufferView*>(exec->argument(0));
3104 uint32_t functionCount = exec->argument(1).toUInt32(exec);
3105
3106 if (exec->argumentCount() != functionCount + 2)
3107 CRASH();
3108
3109 Wasm::Plan plan(&vm, static_cast<uint8_t*>(source->vector()), source->length());
3110 plan.run();
3111 if (plan.failed()) {
3112 dataLogLn("failed to parse module: ", plan.errorMessage());
3113 CRASH();
3114 }
3115
3116 if (plan.internalFunctionCount() != functionCount)
3117 CRASH();
3118
3119 MarkedArgumentBuffer callees;
3120 MarkedArgumentBuffer keepAlive;
3121 {
3122 unsigned lastIndex = UINT_MAX;
3123 plan.initializeCallees(exec->lexicalGlobalObject(),
3124 [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
3125 RELEASE_ASSERT(!calleeIndex || (calleeIndex - 1 == lastIndex));
3126 callees.append(jsEntrypointCallee);
3127 keepAlive.append(wasmEntrypointCallee);
3128 lastIndex = calleeIndex;
3129 });
3130 }
3131 std::unique_ptr<Wasm::ModuleInformation> moduleInformation = plan.takeModuleInformation();
3132 RELEASE_ASSERT(!moduleInformation->memory);
3133
3134 for (uint32_t i = 0; i < functionCount; ++i) {
3135 JSArray* testCases = jsCast<JSArray*>(exec->argument(i + 2));
3136 for (unsigned testIndex = 0; testIndex < testCases->length(); ++testIndex) {
3137 JSArray* test = jsCast<JSArray*>(testCases->getIndexQuickly(testIndex));
3138 JSObject* result = jsCast<JSObject*>(test->getIndexQuickly(0));
3139 JSArray* arguments = jsCast<JSArray*>(test->getIndexQuickly(1));
3140
3141 Vector<JSValue> boxedArgs;
3142 for (unsigned argIndex = 0; argIndex < arguments->length(); ++argIndex)
3143 boxedArgs.append(box(exec, vm, arguments->getIndexQuickly(argIndex)));
3144
3145 JSValue callResult;
3146 {
3147 auto scope = DECLARE_THROW_SCOPE(vm);
3148 callResult = callWasmFunction(&vm, exec->lexicalGlobalObject(), jsCast<JSWebAssemblyCallee*>(callees.at(i)), boxedArgs);
3149 RETURN_IF_EXCEPTION(scope, { });
3150 }
3151 JSValue expected = box(exec, vm, result);
3152 if (callResult != expected) {
3153 dataLog("Arguments: ");
3154 CommaPrinter comma(", ");
3155 for (unsigned argIndex = 0; argIndex < arguments->length(); ++argIndex)
3156 dataLog(comma, valueWithTypeOfWasmValue(exec, vm, boxedArgs[argIndex], arguments->getIndexQuickly(argIndex)));
3157 dataLogLn();
3158
3159 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, toCString(" (callResult == ", valueWithTypeOfWasmValue(exec, vm, callResult, result), ", expected == ", valueWithTypeOfWasmValue(exec, vm, expected, result), ")").data());
3160 CRASH();
3161 }
3162 }
3163 }
3164
3165 return encodedJSUndefined();
3166}
3167
3168#endif // ENABLE(WEBASSEBLY)
3169
3170// Use SEH for Release builds only to get rid of the crash report dialog
3171// (luckily the same tests fail in Release and Debug builds so far). Need to
3172// be in a separate main function because the jscmain function requires object
3173// unwinding.
3174
3175#if COMPILER(MSVC) && !defined(_DEBUG)
3176#define TRY __try {
3177#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
3178#else
3179#define TRY
3180#define EXCEPT(x)
3181#endif
3182
3183int jscmain(int argc, char** argv);
3184
3185static double s_desiredTimeout;
3186static double s_timeoutMultiplier = 1.0;
3187
3188static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
3189{
3190 Seconds timeoutDuration(s_desiredTimeout * s_timeoutMultiplier);
3191 sleep(timeoutDuration);
3192 dataLog("Timed out after ", timeoutDuration, " seconds!\n");
3193 CRASH();
3194}
3195
3196static void startTimeoutThreadIfNeeded()
3197{
3198 if (char* timeoutString = getenv("JSCTEST_timeout")) {
3199 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
3200 dataLog("WARNING: timeout string is malformed, got ", timeoutString,
3201 " but expected a number. Not using a timeout.\n");
3202 } else
3203 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
3204 }
3205}
3206
3207int main(int argc, char** argv)
3208{
3209#if PLATFORM(IOS) && CPU(ARM_THUMB2)
3210 // Enabled IEEE754 denormal support.
3211 fenv_t env;
3212 fegetenv( &env );
3213 env.__fpscr &= ~0x01000000u;
3214 fesetenv( &env );
3215#endif
3216
3217#if OS(WINDOWS)
3218 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
3219 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
3220 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
3221 ::SetErrorMode(0);
3222
3223#if defined(_DEBUG)
3224 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
3225 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3226 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
3227 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
3228 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
3229 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
3230#endif
3231
3232 timeBeginPeriod(1);
3233#endif
3234
3235#if PLATFORM(EFL)
3236 ecore_init();
3237#endif
3238
3239#if PLATFORM(GTK)
3240 if (!setlocale(LC_ALL, ""))
3241 WTFLogAlways("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
3242#endif
3243
3244 // Need to initialize WTF threading before we start any threads. Cannot initialize JSC
3245 // threading yet, since that would do somethings that we'd like to defer until after we
3246 // have a chance to parse options.
3247 WTF::initializeThreading();
3248
3249#if PLATFORM(IOS)
3250 Options::crashIfCantAllocateJITMemory() = true;
3251#endif
3252
3253 // We can't use destructors in the following code because it uses Windows
3254 // Structured Exception Handling
3255 int res = 0;
3256 TRY
3257 res = jscmain(argc, argv);
3258 EXCEPT(res = 3)
3259 finalizeStatsAtEndOfTesting();
3260
3261#if PLATFORM(EFL)
3262 ecore_shutdown();
3263#endif
3264
3265 jscExit(res);
3266}
3267
3268static void dumpException(GlobalObject* globalObject, JSValue exception)
3269{
3270 VM& vm = globalObject->vm();
3271 auto scope = DECLARE_CATCH_SCOPE(vm);
3272
3273#define CHECK_EXCEPTION() do { \
3274 if (scope.exception()) { \
3275 scope.clearException(); \
3276 return; \
3277 } \
3278 } while (false)
3279
3280 printf("Exception: %s\n", exception.toWTFString(globalObject->globalExec()).utf8().data());
3281
3282 Identifier nameID = Identifier::fromString(globalObject->globalExec(), "name");
3283 Identifier fileNameID = Identifier::fromString(globalObject->globalExec(), "sourceURL");
3284 Identifier lineNumberID = Identifier::fromString(globalObject->globalExec(), "line");
3285 Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
3286
3287 JSValue nameValue = exception.get(globalObject->globalExec(), nameID);
3288 CHECK_EXCEPTION();
3289 JSValue fileNameValue = exception.get(globalObject->globalExec(), fileNameID);
3290 CHECK_EXCEPTION();
3291 JSValue lineNumberValue = exception.get(globalObject->globalExec(), lineNumberID);
3292 CHECK_EXCEPTION();
3293 JSValue stackValue = exception.get(globalObject->globalExec(), stackID);
3294 CHECK_EXCEPTION();
3295
3296 if (nameValue.toWTFString(globalObject->globalExec()) == "SyntaxError"
3297 && (!fileNameValue.isUndefinedOrNull() || !lineNumberValue.isUndefinedOrNull())) {
3298 printf(
3299 "at %s:%s\n",
3300 fileNameValue.toWTFString(globalObject->globalExec()).utf8().data(),
3301 lineNumberValue.toWTFString(globalObject->globalExec()).utf8().data());
3302 }
3303
3304 if (!stackValue.isUndefinedOrNull())
3305 printf("%s\n", stackValue.toWTFString(globalObject->globalExec()).utf8().data());
3306
3307#undef CHECK_EXCEPTION
3308}
3309
3310static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue exception, const String& expectedExceptionName, bool alwaysDumpException)
3311{
3312 auto scope = DECLARE_CATCH_SCOPE(vm);
3313 scope.clearException();
3314 if (!exception) {
3315 printf("Expected uncaught exception with name '%s' but none was thrown\n", expectedExceptionName.utf8().data());
3316 return false;
3317 }
3318
3319 ExecState* exec = globalObject->globalExec();
3320 JSValue exceptionClass = globalObject->get(exec, Identifier::fromString(exec, expectedExceptionName));
3321 if (!exceptionClass.isObject() || scope.exception()) {
3322 printf("Expected uncaught exception with name '%s' but given exception class is not defined\n", expectedExceptionName.utf8().data());
3323 return false;
3324 }
3325
3326 bool isInstanceOfExpectedException = jsCast<JSObject*>(exceptionClass)->hasInstance(exec, exception);
3327 if (scope.exception()) {
3328 printf("Expected uncaught exception with name '%s' but given exception class fails performing hasInstance\n", expectedExceptionName.utf8().data());
3329 return false;
3330 }
3331 if (isInstanceOfExpectedException) {
3332 if (alwaysDumpException)
3333 dumpException(globalObject, exception);
3334 return true;
3335 }
3336
3337 printf("Expected uncaught exception with name '%s' but exception value is not instance of this exception class\n", expectedExceptionName.utf8().data());
3338 dumpException(globalObject, exception);
3339 return false;
3340}
3341
3342static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool& success)
3343{
3344 VM& vm = globalObject->vm();
3345 if (!uncaughtExceptionName || !isLastFile) {
3346 success = success && !hasException;
3347 if (dump && !hasException)
3348 printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
3349 if (hasException)
3350 dumpException(globalObject, value);
3351 } else
3352 success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
3353}
3354
3355static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool module)
3356{
3357 String fileName;
3358 Vector<char> scriptBuffer;
3359
3360 if (dump)
3361 JSC::Options::dumpGeneratedBytecodes() = true;
3362
3363 VM& vm = globalObject->vm();
3364 auto scope = DECLARE_CATCH_SCOPE(vm);
3365 bool success = true;
3366
3367#if ENABLE(SAMPLING_FLAGS)
3368 SamplingFlags::start();
3369#endif
3370
3371 for (size_t i = 0; i < scripts.size(); i++) {
3372 JSInternalPromise* promise = nullptr;
3373 bool isModule = module || scripts[i].scriptType == Script::ScriptType::Module;
3374 if (scripts[i].codeSource == Script::CodeSource::File) {
3375 fileName = scripts[i].argument;
3376 if (scripts[i].strictMode == Script::StrictMode::Strict)
3377 scriptBuffer.append("\"use strict\";\n", strlen("\"use strict\";\n"));
3378
3379 if (isModule)
3380 promise = loadAndEvaluateModule(globalObject->globalExec(), fileName);
3381 else {
3382 if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer))
3383 return false; // fail early so we can catch missing files
3384 }
3385 } else {
3386 size_t commandLineLength = strlen(scripts[i].argument);
3387 scriptBuffer.resize(commandLineLength);
3388 std::copy(scripts[i].argument, scripts[i].argument + commandLineLength, scriptBuffer.begin());
3389 fileName = ASCIILiteral("[Command Line]");
3390 }
3391
3392 bool isLastFile = i == scripts.size() - 1;
3393 if (isModule) {
3394 if (!promise)
3395 promise = loadAndEvaluateModule(globalObject->globalExec(), makeSource(stringFromUTF(scriptBuffer), SourceOrigin { absolutePath(fileName) }, fileName, TextPosition(), SourceProviderSourceType::Module));
3396 scope.clearException();
3397
3398 JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
3399 checkException(globalObject, isLastFile, false, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
3400 return JSValue::encode(jsUndefined());
3401 });
3402
3403 JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
3404 checkException(globalObject, isLastFile, true, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
3405 return JSValue::encode(jsUndefined());
3406 });
3407
3408 promise->then(globalObject->globalExec(), fulfillHandler, rejectHandler);
3409 vm.drainMicrotasks();
3410 } else {
3411 NakedPtr<Exception> evaluationException;
3412 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
3413 ASSERT(!scope.exception());
3414 if (evaluationException)
3415 returnValue = evaluationException->value();
3416 checkException(globalObject, isLastFile, evaluationException, returnValue, uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
3417 }
3418
3419 scriptBuffer.clear();
3420 scope.clearException();
3421 }
3422
3423#if ENABLE(REGEXP_TRACING)
3424 vm.dumpRegExpTrace();
3425#endif
3426 return success;
3427}
3428
3429#define RUNNING_FROM_XCODE 0
3430
3431static void runInteractive(GlobalObject* globalObject)
3432{
3433 VM& vm = globalObject->vm();
3434 auto scope = DECLARE_CATCH_SCOPE(vm);
3435
3436 std::optional<DirectoryName> directoryName = currentWorkingDirectory();
3437 if (!directoryName)
3438 return;
3439 SourceOrigin sourceOrigin(resolvePath(directoryName.value(), ModuleName("interpreter")));
3440
3441 bool shouldQuit = false;
3442 while (!shouldQuit) {
3443#if HAVE(READLINE) && !RUNNING_FROM_XCODE
3444 ParserError error;
3445 String source;
3446 do {
3447 error = ParserError();
3448 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
3449 shouldQuit = !line;
3450 if (!line)
3451 break;
3452 source = source + line;
3453 source = source + '\n';
3454 checkSyntax(globalObject->vm(), makeSource(source, sourceOrigin), error);
3455 if (!line[0]) {
3456 free(line);
3457 break;
3458 }
3459 add_history(line);
3460 free(line);
3461 } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable);
3462
3463 if (error.isValid()) {
3464 printf("%s:%d\n", error.message().utf8().data(), error.line());
3465 continue;
3466 }
3467
3468
3469 NakedPtr<Exception> evaluationException;
3470 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, sourceOrigin), JSValue(), evaluationException);
3471#else
3472 printf("%s", interactivePrompt);
3473 Vector<char, 256> line;
3474 int c;
3475 while ((c = getchar()) != EOF) {
3476 // FIXME: Should we also break on \r?
3477 if (c == '\n')
3478 break;
3479 line.append(c);
3480 }
3481 if (line.isEmpty())
3482 break;
3483
3484 NakedPtr<Exception> evaluationException;
3485 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, sourceOrigin, sourceOrigin.string()), JSValue(), evaluationException);
3486#endif
3487 if (evaluationException)
3488 printf("Exception: %s\n", evaluationException->value().toWTFString(globalObject->globalExec()).utf8().data());
3489 else
3490 printf("%s\n", returnValue.toWTFString(globalObject->globalExec()).utf8().data());
3491
3492 scope.clearException();
3493 globalObject->vm().drainMicrotasks();
3494 }
3495 printf("\n");
3496}
3497
3498static NO_RETURN void printUsageStatement(bool help = false)
3499{
3500 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
3501 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
3502 fprintf(stderr, " -e Evaluate argument as script code\n");
3503 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
3504 fprintf(stderr, " -h|--help Prints this help message\n");
3505 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
3506 fprintf(stderr, " -m Execute as a module\n");
3507#if HAVE(SIGNAL_H)
3508 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
3509#endif
3510 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
3511 fprintf(stderr, " -x Output exit code before terminating\n");
3512 fprintf(stderr, "\n");
3513 fprintf(stderr, " --sample Collects and outputs sampling profiler data\n");
3514 fprintf(stderr, " --test262-async Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n");
3515 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");
3516 fprintf(stderr, " --module-file=<file> Parse and evaluate the given file as module (this option may be passed more than once)\n");
3517 fprintf(stderr, " --exception=<name> Check the last script exits with an uncaught exception with the specified name\n");
3518 fprintf(stderr, " --dumpException Dump uncaught exception text\n");
3519 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
3520 fprintf(stderr, " --dumpOptions Dumps all non-default JSC VM options before continuing\n");
3521 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
3522 fprintf(stderr, "\n");
3523
3524 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
3525}
3526
3527void CommandLine::parseArguments(int argc, char** argv)
3528{
3529 Options::initialize();
3530
3531 int i = 1;
3532 JSC::Options::DumpLevel dumpOptionsLevel = JSC::Options::DumpLevel::None;
3533 bool needToExit = false;
3534
3535 bool hasBadJSCOptions = false;
3536 for (; i < argc; ++i) {
3537 const char* arg = argv[i];
3538 if (!strcmp(arg, "-f")) {
3539 if (++i == argc)
3540 printUsageStatement();
3541 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
3542 continue;
3543 }
3544 if (!strcmp(arg, "-e")) {
3545 if (++i == argc)
3546 printUsageStatement();
3547 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::CommandLine, Script::ScriptType::Script, argv[i]));
3548 continue;
3549 }
3550 if (!strcmp(arg, "-i")) {
3551 m_interactive = true;
3552 continue;
3553 }
3554 if (!strcmp(arg, "-d")) {
3555 m_dump = true;
3556 continue;
3557 }
3558 if (!strcmp(arg, "-p")) {
3559 if (++i == argc)
3560 printUsageStatement();
3561 m_profile = true;
3562 m_profilerOutput = argv[i];
3563 continue;
3564 }
3565 if (!strcmp(arg, "-m")) {
3566 m_module = true;
3567 continue;
3568 }
3569 if (!strcmp(arg, "-s")) {
3570#if HAVE(SIGNAL_H)
3571 signal(SIGILL, _exit);
3572 signal(SIGFPE, _exit);
3573 signal(SIGBUS, _exit);
3574 signal(SIGSEGV, _exit);
3575#endif
3576 continue;
3577 }
3578 if (!strcmp(arg, "-x")) {
3579 m_exitCode = true;
3580 continue;
3581 }
3582 if (!strcmp(arg, "--")) {
3583 ++i;
3584 break;
3585 }
3586 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
3587 printUsageStatement(true);
3588
3589 if (!strcmp(arg, "--options")) {
3590 dumpOptionsLevel = JSC::Options::DumpLevel::Verbose;
3591 needToExit = true;
3592 continue;
3593 }
3594 if (!strcmp(arg, "--dumpOptions")) {
3595 dumpOptionsLevel = JSC::Options::DumpLevel::Overridden;
3596 continue;
3597 }
3598 if (!strcmp(arg, "--sample")) {
3599 JSC::Options::useSamplingProfiler() = true;
3600 JSC::Options::collectSamplingProfilerDataForJSCShell() = true;
3601 m_dumpSamplingProfilerData = true;
3602 continue;
3603 }
3604
3605 static const char* timeoutMultiplierOptStr = "--timeoutMultiplier=";
3606 static const unsigned timeoutMultiplierOptStrLength = strlen(timeoutMultiplierOptStr);
3607 if (!strncmp(arg, timeoutMultiplierOptStr, timeoutMultiplierOptStrLength)) {
3608 const char* valueStr = &arg[timeoutMultiplierOptStrLength];
3609 if (sscanf(valueStr, "%lf", &s_timeoutMultiplier) != 1)
3610 dataLog("WARNING: --timeoutMultiplier=", valueStr, " is invalid. Expects a numeric ratio.\n");
3611 continue;
3612 }
3613
3614 if (!strcmp(arg, "--test262-async")) {
3615 test262AsyncTest = true;
3616 continue;
3617 }
3618
3619 if (!strcmp(arg, "--remote-debug")) {
3620 m_enableRemoteDebugging = true;
3621 continue;
3622 }
3623
3624 static const unsigned strictFileStrLength = strlen("--strict-file=");
3625 if (!strncmp(arg, "--strict-file=", strictFileStrLength)) {
3626 m_scripts.append(Script(Script::StrictMode::Strict, Script::CodeSource::File, Script::ScriptType::Script, argv[i] + strictFileStrLength));
3627 continue;
3628 }
3629
3630 static const unsigned moduleFileStrLength = strlen("--module-file=");
3631 if (!strncmp(arg, "--module-file=", moduleFileStrLength)) {
3632 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Module, argv[i] + moduleFileStrLength));
3633 continue;
3634 }
3635
3636 if (!strcmp(arg, "--dumpException")) {
3637 m_alwaysDumpUncaughtException = true;
3638 continue;
3639 }
3640
3641 static const unsigned exceptionStrLength = strlen("--exception=");
3642 if (!strncmp(arg, "--exception=", exceptionStrLength)) {
3643 m_uncaughtExceptionName = String(arg + exceptionStrLength);
3644 continue;
3645 }
3646
3647 // See if the -- option is a JSC VM option.
3648 if (strstr(arg, "--") == arg) {
3649 if (!JSC::Options::setOption(&arg[2])) {
3650 hasBadJSCOptions = true;
3651 dataLog("ERROR: invalid option: ", arg, "\n");
3652 }
3653 continue;
3654 }
3655
3656 // This arg is not recognized by the VM nor by jsc. Pass it on to the
3657 // script.
3658 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
3659 }
3660
3661 if (hasBadJSCOptions && JSC::Options::validateOptions())
3662 CRASH();
3663
3664 if (m_scripts.isEmpty())
3665 m_interactive = true;
3666
3667 for (; i < argc; ++i)
3668 m_arguments.append(argv[i]);
3669
3670 if (dumpOptionsLevel != JSC::Options::DumpLevel::None) {
3671 const char* optionsTitle = (dumpOptionsLevel == JSC::Options::DumpLevel::Overridden)
3672 ? "Modified JSC runtime options:"
3673 : "All JSC runtime options:";
3674 JSC::Options::dumpAllOptions(stderr, dumpOptionsLevel, optionsTitle);
3675 }
3676 JSC::Options::ensureOptionsAreCoherent();
3677 if (needToExit)
3678 jscExit(EXIT_SUCCESS);
3679}
3680
3681template<typename Func>
3682int runJSC(CommandLine options, const Func& func)
3683{
3684 Worker worker(Workers::singleton());
3685
3686 VM& vm = VM::create(LargeHeap).leakRef();
3687 JSLockHolder locker(&vm);
3688
3689 int result;
3690 if (options.m_profile && !vm.m_perBytecodeProfiler)
3691 vm.m_perBytecodeProfiler = std::make_unique<Profiler::Database>(vm);
3692
3693 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
3694 globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
3695 bool success = func(vm, globalObject);
3696 if (options.m_interactive && success)
3697 runInteractive(globalObject);
3698
3699 vm.drainMicrotasks();
3700 result = success && (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
3701
3702 if (options.m_exitCode)
3703 printf("jsc exiting %d\n", result);
3704
3705 if (options.m_profile) {
3706 if (!vm.m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
3707 fprintf(stderr, "could not save profiler output.\n");
3708 }
3709
3710#if ENABLE(JIT)
3711 if (Options::useExceptionFuzz())
3712 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
3713 bool fireAtEnabled =
3714 Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
3715 if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
3716 printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
3717 if (Options::useOSRExitFuzz()) {
3718 printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks());
3719 printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks());
3720 }
3721
3722 auto compileTimeStats = JIT::compileTimeStats();
3723 Vector<CString> compileTimeKeys;
3724 for (auto& entry : compileTimeStats)
3725 compileTimeKeys.append(entry.key);
3726 std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
3727 for (CString key : compileTimeKeys)
3728 printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
3729#endif
3730
3731 if (Options::gcAtEnd()) {
3732 // We need to hold the API lock to do a GC.
3733 JSLockHolder locker(&vm);
3734 vm.heap.collectAllGarbage();
3735 }
3736
3737 if (options.m_dumpSamplingProfilerData) {
3738#if ENABLE(SAMPLING_PROFILER)
3739 JSLockHolder locker(&vm);
3740 vm.samplingProfiler()->reportTopFunctions();
3741 vm.samplingProfiler()->reportTopBytecodes();
3742#else
3743 dataLog("Sampling profiler is not enabled on this platform\n");
3744#endif
3745 }
3746
3747 return result;
3748}
3749
3750int jscmain(int argc, char** argv)
3751{
3752 // Need to override and enable restricted options before we start parsing options below.
3753 Options::enableRestrictedOptions(true);
3754
3755 // Note that the options parsing can affect VM creation, and thus
3756 // comes first.
3757 CommandLine options(argc, argv);
3758
3759 // Initialize JSC before getting VM.
3760 WTF::initializeMainThread();
3761 JSC::initializeThreading();
3762 startTimeoutThreadIfNeeded();
3763
3764 int result;
3765 result = runJSC(
3766 options,
3767 [&] (VM&, GlobalObject* globalObject) {
3768 return runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
3769 });
3770
3771 printSuperSamplerState();
3772
3773 return result;
3774}
3775
3776#if OS(WINDOWS)
3777extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
3778{
3779 return main(argc, const_cast<char**>(argv));
3780}
3781#endif
Note: See TracBrowser for help on using the repository browser.