a96253a3fc34bde0f1ff928d20a95a508e4051cb
[WebKit-https.git] / Source / JavaScriptCore / jsc.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004-2008, 2012-2013, 2015-2016 Apple Inc. All rights reserved.
4  *  Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com)
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 "ArrayPrototype.h"
26 #include "BuiltinExecutableCreator.h"
27 #include "ButterflyInlines.h"
28 #include "CodeBlock.h"
29 #include "Completion.h"
30 #include "Disassembler.h"
31 #include "Exception.h"
32 #include "ExceptionHelpers.h"
33 #include "GetterSetter.h"
34 #include "HeapProfiler.h"
35 #include "HeapSnapshotBuilder.h"
36 #include "HeapStatistics.h"
37 #include "InitializeThreading.h"
38 #include "Interpreter.h"
39 #include "JIT.h"
40 #include "JSArray.h"
41 #include "JSArrayBuffer.h"
42 #include "JSCInlines.h"
43 #include "JSFunction.h"
44 #include "JSInternalPromise.h"
45 #include "JSInternalPromiseDeferred.h"
46 #include "JSLock.h"
47 #include "JSNativeStdFunction.h"
48 #include "JSONObject.h"
49 #include "JSProxy.h"
50 #include "JSString.h"
51 #include "JSWASMModule.h"
52 #include "LLIntData.h"
53 #include "ParserError.h"
54 #include "ProfilerDatabase.h"
55 #include "SamplingProfiler.h"
56 #include "ShadowChicken.h"
57 #include "StackVisitor.h"
58 #include "StructureInlines.h"
59 #include "StructureRareDataInlines.h"
60 #include "SuperSampler.h"
61 #include "TestRunnerUtils.h"
62 #include "TypeProfilerLog.h"
63 #include <locale.h>
64 #include <math.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <thread>
69 #include <wtf/CurrentTime.h>
70 #include <wtf/MainThread.h>
71 #include <wtf/StringPrintStream.h>
72 #include <wtf/text/StringBuilder.h>
73
74 #if OS(WINDOWS)
75 #include <direct.h>
76 #else
77 #include <unistd.h>
78 #endif
79
80 #if HAVE(READLINE)
81 // readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
82 // We #define it to something else to avoid this conflict.
83 #define Function ReadlineFunction
84 #include <readline/history.h>
85 #include <readline/readline.h>
86 #undef Function
87 #endif
88
89 #if HAVE(SYS_TIME_H)
90 #include <sys/time.h>
91 #endif
92
93 #if HAVE(SIGNAL_H)
94 #include <signal.h>
95 #endif
96
97 #if COMPILER(MSVC)
98 #include <crtdbg.h>
99 #include <mmsystem.h>
100 #include <windows.h>
101 #endif
102
103 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
104 #include <fenv.h>
105 #include <arm/arch.h>
106 #endif
107
108 #if PLATFORM(EFL)
109 #include <Ecore.h>
110 #endif
111
112 #if !defined(PATH_MAX)
113 #define PATH_MAX 4096
114 #endif
115
116 using namespace JSC;
117 using namespace WTF;
118
119 namespace {
120
121 NO_RETURN_WITH_VALUE static void jscExit(int status)
122 {
123     waitForAsynchronousDisassembly();
124     
125 #if ENABLE(DFG_JIT)
126     if (DFG::isCrashing()) {
127         for (;;) {
128 #if OS(WINDOWS)
129             Sleep(1000);
130 #else
131             pause();
132 #endif
133         }
134     }
135 #endif // ENABLE(DFG_JIT)
136     exit(status);
137 }
138
139 class Element;
140 class ElementHandleOwner;
141 class Masuqerader;
142 class Root;
143 class RuntimeArray;
144
145 class Element : public JSNonFinalObject {
146 public:
147     Element(VM& vm, Structure* structure)
148         : Base(vm, structure)
149     {
150     }
151
152     typedef JSNonFinalObject Base;
153     static const bool needsDestruction = false;
154
155     Root* root() const { return m_root.get(); }
156     void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); }
157
158     static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
159     {
160         Structure* structure = createStructure(vm, globalObject, jsNull());
161         Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure);
162         element->finishCreation(vm, root);
163         return element;
164     }
165
166     void finishCreation(VM&, Root*);
167
168     static void visitChildren(JSCell* cell, SlotVisitor& visitor)
169     {
170         Element* thisObject = jsCast<Element*>(cell);
171         ASSERT_GC_OBJECT_INHERITS(thisObject, info());
172         Base::visitChildren(thisObject, visitor);
173         visitor.append(&thisObject->m_root);
174     }
175
176     static ElementHandleOwner* handleOwner();
177
178     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
179     {
180         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
181     }
182
183     DECLARE_INFO;
184
185 private:
186     WriteBarrier<Root> m_root;
187 };
188
189 class ElementHandleOwner : public WeakHandleOwner {
190 public:
191     virtual bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
192     {
193         Element* element = jsCast<Element*>(handle.slot()->asCell());
194         return visitor.containsOpaqueRoot(element->root());
195     }
196 };
197
198 class Masquerader : public JSNonFinalObject {
199 public:
200     Masquerader(VM& vm, Structure* structure)
201         : Base(vm, structure)
202     {
203     }
204
205     typedef JSNonFinalObject Base;
206     static const unsigned StructureFlags = Base::StructureFlags | JSC::MasqueradesAsUndefined;
207
208     static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
209     {
210         globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(vm, "Masquerading object allocated");
211         Structure* structure = createStructure(vm, globalObject, jsNull());
212         Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
213         result->finishCreation(vm);
214         return result;
215     }
216
217     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
218     {
219         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
220     }
221
222     DECLARE_INFO;
223 };
224
225 class Root : public JSDestructibleObject {
226 public:
227     Root(VM& vm, Structure* structure)
228         : Base(vm, structure)
229     {
230     }
231
232     Element* element()
233     {
234         return m_element.get();
235     }
236
237     void setElement(Element* element)
238     {
239         Weak<Element> newElement(element, Element::handleOwner());
240         m_element.swap(newElement);
241     }
242
243     static Root* create(VM& vm, JSGlobalObject* globalObject)
244     {
245         Structure* structure = createStructure(vm, globalObject, jsNull());
246         Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
247         root->finishCreation(vm);
248         return root;
249     }
250
251     typedef JSDestructibleObject Base;
252
253     DECLARE_INFO;
254     static const bool needsDestruction = true;
255
256     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
257     {
258         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
259     }
260
261     static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
262     {
263         Base::visitChildren(thisObject, visitor);
264         visitor.addOpaqueRoot(thisObject);
265     }
266
267 private:
268     Weak<Element> m_element;
269 };
270
271 class ImpureGetter : public JSNonFinalObject {
272 public:
273     ImpureGetter(VM& vm, Structure* structure)
274         : Base(vm, structure)
275     {
276     }
277
278     DECLARE_INFO;
279     typedef JSNonFinalObject Base;
280     static const unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::OverridesGetOwnPropertySlot;
281
282     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
283     {
284         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
285     }
286
287     static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
288     {
289         ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
290         getter->finishCreation(vm, delegate);
291         return getter;
292     }
293
294     void finishCreation(VM& vm, JSObject* delegate)
295     {
296         Base::finishCreation(vm);
297         if (delegate)
298             m_delegate.set(vm, this, delegate);
299     }
300
301     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
302     {
303         VM& vm = exec->vm();
304         auto scope = DECLARE_THROW_SCOPE(vm);
305         ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
306         
307         if (thisObject->m_delegate) {
308             if (thisObject->m_delegate->getPropertySlot(exec, name, slot))
309                 return true;
310             if (UNLIKELY(scope.exception()))
311                 return false;
312         }
313
314         return Base::getOwnPropertySlot(object, exec, name, slot);
315     }
316
317     static void visitChildren(JSCell* cell, SlotVisitor& visitor)
318     {
319         Base::visitChildren(cell, visitor);
320         ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell);
321         visitor.append(&thisObject->m_delegate);
322     }
323
324     void setDelegate(VM& vm, JSObject* delegate)
325     {
326         m_delegate.set(vm, this, delegate);
327     }
328
329 private:
330     WriteBarrier<JSObject> m_delegate;
331 };
332
333 class CustomGetter : public JSNonFinalObject {
334 public:
335     CustomGetter(VM& vm, Structure* structure)
336         : Base(vm, structure)
337     {
338     }
339
340     DECLARE_INFO;
341     typedef JSNonFinalObject Base;
342     static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot;
343
344     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
345     {
346         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
347     }
348
349     static CustomGetter* create(VM& vm, Structure* structure)
350     {
351         CustomGetter* getter = new (NotNull, allocateCell<CustomGetter>(vm.heap, sizeof(CustomGetter))) CustomGetter(vm, structure);
352         getter->finishCreation(vm);
353         return getter;
354     }
355
356     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
357     {
358         CustomGetter* thisObject = jsCast<CustomGetter*>(object);
359         if (propertyName == PropertyName(Identifier::fromString(exec, "customGetter"))) {
360             slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->customGetter);
361             return true;
362         }
363         return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
364     }
365
366 private:
367     static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
368     {
369         VM& vm = exec->vm();
370         auto scope = DECLARE_THROW_SCOPE(vm);
371
372         CustomGetter* thisObject = jsDynamicCast<CustomGetter*>(JSValue::decode(thisValue));
373         if (!thisObject)
374             return throwVMTypeError(exec, scope);
375         bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow"))).toBoolean(exec);
376         if (shouldThrow)
377             return throwVMTypeError(exec, scope);
378         return JSValue::encode(jsNumber(100));
379     }
380 };
381
382 class RuntimeArray : public JSArray {
383 public:
384     typedef JSArray Base;
385     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
386
387     static RuntimeArray* create(ExecState* exec)
388     {
389         VM& vm = exec->vm();
390         JSGlobalObject* globalObject = exec->lexicalGlobalObject();
391         Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
392         RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
393         runtimeArray->finishCreation(exec);
394         vm.heap.addFinalizer(runtimeArray, destroy);
395         return runtimeArray;
396     }
397
398     ~RuntimeArray() { }
399
400     static void destroy(JSCell* cell)
401     {
402         static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
403     }
404
405     static const bool needsDestruction = false;
406
407     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
408     {
409         RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
410         if (propertyName == exec->propertyNames().length) {
411             slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
412             return true;
413         }
414
415         Optional<uint32_t> index = parseIndex(propertyName);
416         if (index && index.value() < thisObject->getLength()) {
417             slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
418             return true;
419         }
420
421         return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
422     }
423
424     static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
425     {
426         RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
427         if (index < thisObject->getLength()) {
428             slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
429             return true;
430         }
431
432         return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
433     }
434
435     static NO_RETURN_DUE_TO_CRASH bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
436     {
437         RELEASE_ASSERT_NOT_REACHED();
438     }
439
440     static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
441     {
442         RELEASE_ASSERT_NOT_REACHED();
443     }
444
445     unsigned getLength() const { return m_vector.size(); }
446
447     DECLARE_INFO;
448
449     static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
450     {
451         return globalObject->arrayPrototype();
452     }
453
454     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
455     {
456         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
457     }
458
459 protected:
460     void finishCreation(ExecState* exec)
461     {
462         Base::finishCreation(exec->vm());
463         ASSERT(inherits(info()));
464
465         for (size_t i = 0; i < exec->argumentCount(); i++)
466             m_vector.append(exec->argument(i).toInt32(exec));
467     }
468
469 private:
470     RuntimeArray(ExecState* exec, Structure* structure)
471         : JSArray(exec->vm(), structure, 0)
472     {
473     }
474
475     static EncodedJSValue lengthGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
476     {
477         VM& vm = exec->vm();
478         auto scope = DECLARE_THROW_SCOPE(vm);
479
480         RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
481         if (!thisObject)
482             return throwVMTypeError(exec, scope);
483         return JSValue::encode(jsNumber(thisObject->getLength()));
484     }
485
486     Vector<int> m_vector;
487 };
488
489 class SimpleObject : public JSNonFinalObject {
490 public:
491     SimpleObject(VM& vm, Structure* structure)
492         : Base(vm, structure)
493     {
494     }
495
496     typedef JSNonFinalObject Base;
497     static const bool needsDestruction = false;
498
499     static SimpleObject* create(VM& vm, JSGlobalObject* globalObject)
500     {
501         Structure* structure = createStructure(vm, globalObject, jsNull());
502         SimpleObject* simpleObject = new (NotNull, allocateCell<SimpleObject>(vm.heap, sizeof(SimpleObject))) SimpleObject(vm, structure);
503         simpleObject->finishCreation(vm);
504         return simpleObject;
505     }
506
507     static void visitChildren(JSCell* cell, SlotVisitor& visitor)
508     {
509         SimpleObject* thisObject = jsCast<SimpleObject*>(cell);
510         ASSERT_GC_OBJECT_INHERITS(thisObject, info());
511         Base::visitChildren(thisObject, visitor);
512         visitor.append(&thisObject->m_hiddenValue);
513     }
514
515     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
516     {
517         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
518     }
519
520     JSValue hiddenValue()
521     {
522         return m_hiddenValue.get();
523     }
524
525     void setHiddenValue(VM& vm, JSValue value)
526     {
527         ASSERT(value.isCell());
528         m_hiddenValue.set(vm, this, value);
529     }
530
531     DECLARE_INFO;
532
533 private:
534     WriteBarrier<JSC::Unknown> m_hiddenValue;
535 };
536
537
538 const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
539 const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
540 const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
541 const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
542 const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
543 const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
544 const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
545 static bool test262AsyncPassed { false };
546 static bool test262AsyncTest { false };
547
548 ElementHandleOwner* Element::handleOwner()
549 {
550     static ElementHandleOwner* owner = 0;
551     if (!owner)
552         owner = new ElementHandleOwner();
553     return owner;
554 }
555
556 void Element::finishCreation(VM& vm, Root* root)
557 {
558     Base::finishCreation(vm);
559     setRoot(vm, root);
560     m_root->setElement(this);
561 }
562
563 }
564
565 static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
566
567 static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
568 static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
569 static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
570 static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
571 static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
572 static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
573 static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
574
575 static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
576 static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
577 static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
578 static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
579 static EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState*);
580 static EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState*);
581 static EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState*);
582 static EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState*);
583 static EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState*);
584 static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
585 static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
586 static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
587 static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
588 static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
589 static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
590 static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
591 static EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*);
592 static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*);
593 static EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState*);
594 static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState*);
595 #ifndef NDEBUG
596 static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
597 #endif
598 static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
599 static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
600 static EncodedJSValue JSC_HOST_CALL functionRunString(ExecState*);
601 static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
602 static EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState*);
603 static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
604 static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
605 static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
606 static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
607 static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
608 static EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState*);
609 static EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState*);
610 static EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState*);
611 static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
612 static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
613 static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
614 static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
615 static EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState*);
616 static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
617 static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*);
618 static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
619 static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
620 static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
621 static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
622 static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
623 static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
624 static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
625 static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
626 static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
627 static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
628 static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
629 static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
630 static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
631 static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
632 static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*);
633 static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*);
634 static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*);
635 static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*);
636 static EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState*);
637 static EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState*);
638 static EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*);
639 static EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState*);
640 static EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*);
641 static EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState*);
642 #if ENABLE(SAMPLING_PROFILER)
643 static EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState*);
644 static EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState*);
645 #endif
646
647 #if ENABLE(SAMPLING_FLAGS)
648 static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
649 static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
650 #endif
651
652 static EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState*);
653 static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState*);
654 static EncodedJSValue JSC_HOST_CALL functionGetRandomSeed(ExecState*);
655 static EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState*);
656
657 struct Script {
658     enum class StrictMode {
659         Strict,
660         Sloppy
661     };
662
663     enum class ScriptType {
664         Script,
665         Module
666     };
667
668     enum class CodeSource {
669         File,
670         CommandLine
671     };
672
673     StrictMode strictMode;
674     CodeSource codeSource;
675     ScriptType scriptType;
676     char* argument;
677
678     Script(StrictMode strictMode, CodeSource codeSource, ScriptType scriptType, char *argument)
679         : strictMode(strictMode)
680         , codeSource(codeSource)
681         , scriptType(scriptType)
682         , argument(argument)
683     {
684         if (strictMode == StrictMode::Strict)
685             ASSERT(codeSource == CodeSource::File);
686     }
687 };
688
689 class CommandLine {
690 public:
691     CommandLine(int argc, char** argv)
692     {
693         parseArguments(argc, argv);
694     }
695
696     bool m_interactive { false };
697     bool m_dump { false };
698     bool m_module { false };
699     bool m_exitCode { false };
700     Vector<Script> m_scripts;
701     Vector<String> m_arguments;
702     bool m_profile { false };
703     String m_profilerOutput;
704     String m_uncaughtExceptionName;
705     bool m_alwaysDumpUncaughtException { false };
706     bool m_dumpSamplingProfilerData { false };
707
708     void parseArguments(int, char**);
709 };
710
711 static const char interactivePrompt[] = ">>> ";
712
713 class StopWatch {
714 public:
715     void start();
716     void stop();
717     long getElapsedMS(); // call stop() first
718
719 private:
720     double m_startTime;
721     double m_stopTime;
722 };
723
724 void StopWatch::start()
725 {
726     m_startTime = monotonicallyIncreasingTime();
727 }
728
729 void StopWatch::stop()
730 {
731     m_stopTime = monotonicallyIncreasingTime();
732 }
733
734 long StopWatch::getElapsedMS()
735 {
736     return static_cast<long>((m_stopTime - m_startTime) * 1000);
737 }
738
739 template<typename Vector>
740 static inline String stringFromUTF(const Vector& utf8)
741 {
742     return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size());
743 }
744
745 template<typename Vector>
746 static inline SourceCode jscSource(const Vector& utf8, const String& filename)
747 {
748     String str = stringFromUTF(utf8);
749     return makeSource(str, filename);
750 }
751
752 class GlobalObject : public JSGlobalObject {
753 private:
754     GlobalObject(VM&, Structure*);
755
756 public:
757     typedef JSGlobalObject Base;
758
759     static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
760     {
761         GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
762         object->finishCreation(vm, arguments);
763         vm.heap.addFinalizer(object, destroy);
764         return object;
765     }
766
767     static const bool needsDestruction = false;
768
769     DECLARE_INFO;
770     static const GlobalObjectMethodTable s_globalObjectMethodTable;
771
772     static Structure* createStructure(VM& vm, JSValue prototype)
773     {
774         return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
775     }
776
777     static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags::createAllEnabled(); }
778
779 protected:
780     void finishCreation(VM& vm, const Vector<String>& arguments)
781     {
782         Base::finishCreation(vm);
783         
784         addFunction(vm, "debug", functionDebug, 1);
785         addFunction(vm, "describe", functionDescribe, 1);
786         addFunction(vm, "describeArray", functionDescribeArray, 1);
787         addFunction(vm, "print", functionPrintStdOut, 1);
788         addFunction(vm, "printErr", functionPrintStdErr, 1);
789         addFunction(vm, "quit", functionQuit, 0);
790         addFunction(vm, "abort", functionAbort, 0);
791         addFunction(vm, "gc", functionGCAndSweep, 0);
792         addFunction(vm, "fullGC", functionFullGC, 0);
793         addFunction(vm, "edenGC", functionEdenGC, 0);
794         addFunction(vm, "forceGCSlowPaths", functionForceGCSlowPaths, 0);
795         addFunction(vm, "gcHeapSize", functionHeapSize, 0);
796         addFunction(vm, "addressOf", functionAddressOf, 1);
797         addFunction(vm, "getGetterSetter", functionGetGetterSetter, 2);
798 #ifndef NDEBUG
799         addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
800 #endif
801         addFunction(vm, "version", functionVersion, 1);
802         addFunction(vm, "run", functionRun, 1);
803         addFunction(vm, "runString", functionRunString, 1);
804         addFunction(vm, "load", functionLoad, 1);
805         addFunction(vm, "loadString", functionLoadString, 1);
806         addFunction(vm, "readFile", functionReadFile, 1);
807         addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
808         addFunction(vm, "jscStack", functionJSCStack, 1);
809         addFunction(vm, "readline", functionReadline, 0);
810         addFunction(vm, "preciseTime", functionPreciseTime, 0);
811         addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
812         addFunction(vm, "noInline", functionNeverInlineFunction, 1);
813         addFunction(vm, "noDFG", functionNoDFG, 1);
814         addFunction(vm, "noFTL", functionNoFTL, 1);
815         addFunction(vm, "noOSRExitFuzzing", functionNoOSRExitFuzzing, 1);
816         addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
817         addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
818         addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
819         addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
820         addFunction(vm, "failNextNewCodeBlock", functionFailNextNewCodeBlock, 1);
821 #if ENABLE(SAMPLING_FLAGS)
822         addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
823         addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
824 #endif
825         addFunction(vm, "shadowChickenFunctionsOnStack", functionShadowChickenFunctionsOnStack, 0);
826         addFunction(vm, "setGlobalConstRedeclarationShouldNotThrow", functionSetGlobalConstRedeclarationShouldNotThrow, 0);
827         addConstructableFunction(vm, "Root", functionCreateRoot, 0);
828         addConstructableFunction(vm, "Element", functionCreateElement, 1);
829         addFunction(vm, "getElement", functionGetElement, 1);
830         addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
831         
832         addConstructableFunction(vm, "SimpleObject", functionCreateSimpleObject, 0);
833         addFunction(vm, "getHiddenValue", functionGetHiddenValue, 1);
834         addFunction(vm, "setHiddenValue", functionSetHiddenValue, 2);
835         
836         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum);
837         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum);
838         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum);
839         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum);
840         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, DontEnum);
841         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum);
842         
843         addFunction(vm, "effectful42", functionEffectful42, 0);
844         addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
845         addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
846
847         addFunction(vm, "createProxy", functionCreateProxy, 1);
848         addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
849
850         addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
851         addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
852         addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
853         addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
854         addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
855
856         addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
857         addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
858         addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
859
860         addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
861         addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
862         addFunction(vm, "basicBlockExecutionCount", functionBasicBlockExecutionCount, 2);
863
864         addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
865
866         addFunction(vm, "drainMicrotasks", functionDrainMicrotasks, 0);
867
868         addFunction(vm, "getRandomSeed", functionGetRandomSeed, 0);
869         addFunction(vm, "setRandomSeed", functionSetRandomSeed, 1);
870
871         addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
872
873         addFunction(vm, "loadModule", functionLoadModule, 1);
874         addFunction(vm, "checkModuleSyntax", functionCheckModuleSyntax, 1);
875
876         addFunction(vm, "platformSupportsSamplingProfiler", functionPlatformSupportsSamplingProfiler, 0);
877         addFunction(vm, "generateHeapSnapshot", functionGenerateHeapSnapshot, 0);
878         addFunction(vm, "resetSuperSamplerState", functionResetSuperSamplerState, 0);
879         addFunction(vm, "ensureArrayStorage", functionEnsureArrayStorage, 0);
880 #if ENABLE(SAMPLING_PROFILER)
881         addFunction(vm, "startSamplingProfiler", functionStartSamplingProfiler, 0);
882         addFunction(vm, "samplingProfilerStackTraces", functionSamplingProfilerStackTraces, 0);
883 #endif
884
885         if (!arguments.isEmpty()) {
886             JSArray* array = constructEmptyArray(globalExec(), 0);
887             for (size_t i = 0; i < arguments.size(); ++i)
888                 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
889             putDirect(vm, Identifier::fromString(globalExec(), "arguments"), array);
890         }
891
892         putDirect(vm, Identifier::fromString(globalExec(), "console"), jsUndefined());
893     }
894
895     void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
896     {
897         Identifier identifier = Identifier::fromString(&vm, name);
898         putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
899     }
900     
901     void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
902     {
903         Identifier identifier = Identifier::fromString(&vm, name);
904         putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
905     }
906
907     static JSInternalPromise* moduleLoaderResolve(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
908     static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue);
909 };
910
911 const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, nullptr, CREATE_METHOD_TABLE(GlobalObject) };
912 const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, nullptr, nullptr };
913
914
915 GlobalObject::GlobalObject(VM& vm, Structure* structure)
916     : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
917 {
918 }
919
920 static UChar pathSeparator()
921 {
922 #if OS(WINDOWS)
923     return '\\';
924 #else
925     return '/';
926 #endif
927 }
928
929 struct DirectoryName {
930     // In unix, it is "/". In Windows, it becomes a drive letter like "C:\"
931     String rootName;
932
933     // If the directory name is "/home/WebKit", this becomes "home/WebKit". If the directory name is "/", this becomes "".
934     String queryName;
935 };
936
937 struct ModuleName {
938     ModuleName(const String& moduleName);
939
940     bool startsWithRoot() const
941     {
942         return !queries.isEmpty() && queries[0].isEmpty();
943     }
944
945     Vector<String> queries;
946 };
947
948 ModuleName::ModuleName(const String& moduleName)
949 {
950     // A module name given from code is represented as the UNIX style path. Like, `./A/B.js`.
951     moduleName.split('/', true, queries);
952 }
953
954 static bool extractDirectoryName(const String& absolutePathToFile, DirectoryName& directoryName)
955 {
956     size_t firstSeparatorPosition = absolutePathToFile.find(pathSeparator());
957     if (firstSeparatorPosition == notFound)
958         return false;
959     directoryName.rootName = absolutePathToFile.substring(0, firstSeparatorPosition + 1); // Include the separator.
960     size_t lastSeparatorPosition = absolutePathToFile.reverseFind(pathSeparator());
961     ASSERT_WITH_MESSAGE(lastSeparatorPosition != notFound, "If the separator is not found, this function already returns when performing the forward search.");
962     if (firstSeparatorPosition == lastSeparatorPosition)
963         directoryName.queryName = StringImpl::empty();
964     else {
965         size_t queryStartPosition = firstSeparatorPosition + 1;
966         size_t queryLength = lastSeparatorPosition - queryStartPosition; // Not include the last separator.
967         directoryName.queryName = absolutePathToFile.substring(queryStartPosition, queryLength);
968     }
969     return true;
970 }
971
972 static bool currentWorkingDirectory(DirectoryName& directoryName)
973 {
974 #if OS(WINDOWS)
975     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364934.aspx
976     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
977     // The _MAX_PATH in Windows is 260. If the path of the current working directory is longer than that, _getcwd truncates the result.
978     // And other I/O functions taking a path name also truncate it. To avoid this situation,
979     //
980     // (1). When opening the file in Windows for modules, we always use the abosolute path and add "\\?\" prefix to the path name.
981     // (2). When retrieving the current working directory, use GetCurrentDirectory instead of _getcwd.
982     //
983     // In the path utility functions inside the JSC shell, we does not handle the UNC and UNCW including the network host name.
984     DWORD bufferLength = ::GetCurrentDirectoryW(0, nullptr);
985     if (!bufferLength)
986         return false;
987     // In Windows, wchar_t is the UTF-16LE.
988     // https://msdn.microsoft.com/en-us/library/dd374081.aspx
989     // https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407.aspx
990     auto buffer = std::make_unique<wchar_t[]>(bufferLength);
991     DWORD lengthNotIncludingNull = ::GetCurrentDirectoryW(bufferLength, buffer.get());
992     static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
993     String directoryString = String(reinterpret_cast<UChar*>(buffer.get()));
994     // We don't support network path like \\host\share\<path name>.
995     if (directoryString.startsWith("\\\\"))
996         return false;
997 #else
998     auto buffer = std::make_unique<char[]>(PATH_MAX);
999     if (!getcwd(buffer.get(), PATH_MAX))
1000         return false;
1001     String directoryString = String::fromUTF8(buffer.get());
1002 #endif
1003     if (directoryString.isEmpty())
1004         return false;
1005
1006     if (directoryString[directoryString.length() - 1] == pathSeparator())
1007         return extractDirectoryName(directoryString, directoryName);
1008     // Append the seperator to represents the file name. extractDirectoryName only accepts the absolute file name.
1009     return extractDirectoryName(makeString(directoryString, pathSeparator()), directoryName);
1010 }
1011
1012 static String resolvePath(const DirectoryName& directoryName, const ModuleName& moduleName)
1013 {
1014     Vector<String> directoryPieces;
1015     directoryName.queryName.split(pathSeparator(), false, directoryPieces);
1016
1017     // Only first '/' is recognized as the path from the root.
1018     if (moduleName.startsWithRoot())
1019         directoryPieces.clear();
1020
1021     for (const auto& query : moduleName.queries) {
1022         if (query == String(ASCIILiteral(".."))) {
1023             if (!directoryPieces.isEmpty())
1024                 directoryPieces.removeLast();
1025         } else if (!query.isEmpty() && query != String(ASCIILiteral(".")))
1026             directoryPieces.append(query);
1027     }
1028
1029     StringBuilder builder;
1030     builder.append(directoryName.rootName);
1031     for (size_t i = 0; i < directoryPieces.size(); ++i) {
1032         builder.append(directoryPieces[i]);
1033         if (i + 1 != directoryPieces.size())
1034             builder.append(pathSeparator());
1035     }
1036     return builder.toString();
1037 }
1038
1039 JSInternalPromise* GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue)
1040 {
1041     VM& vm = globalObject->vm();
1042     auto scope = DECLARE_CATCH_SCOPE(vm);
1043
1044     JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1045     const Identifier key = keyValue.toPropertyKey(exec);
1046     if (UNLIKELY(scope.exception())) {
1047         JSValue exception = scope.exception();
1048         scope.clearException();
1049         return deferred->reject(exec, exception);
1050     }
1051
1052     if (key.isSymbol())
1053         return deferred->resolve(exec, keyValue);
1054
1055     DirectoryName directoryName;
1056     if (referrerValue.isUndefined()) {
1057         if (!currentWorkingDirectory(directoryName))
1058             return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1059     } else {
1060         const Identifier referrer = referrerValue.toPropertyKey(exec);
1061         if (UNLIKELY(scope.exception())) {
1062             JSValue exception = scope.exception();
1063             scope.clearException();
1064             return deferred->reject(exec, exception);
1065         }
1066         if (referrer.isSymbol()) {
1067             if (!currentWorkingDirectory(directoryName))
1068                 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1069         } else {
1070             // If the referrer exists, we assume that the referrer is the correct absolute path.
1071             if (!extractDirectoryName(referrer.impl(), directoryName))
1072                 return deferred->reject(exec, createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
1073         }
1074     }
1075
1076     return deferred->resolve(exec, jsString(exec, resolvePath(directoryName, ModuleName(key.impl()))));
1077 }
1078
1079 static void convertShebangToJSComment(Vector<char>& buffer)
1080 {
1081     if (buffer.size() >= 2) {
1082         if (buffer[0] == '#' && buffer[1] == '!')
1083             buffer[0] = buffer[1] = '/';
1084     }
1085 }
1086
1087 static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
1088 {
1089     // We might have injected "use strict"; at the top.
1090     size_t initialSize = buffer.size();
1091     fseek(file, 0, SEEK_END);
1092     size_t bufferCapacity = ftell(file);
1093     fseek(file, 0, SEEK_SET);
1094     buffer.resize(bufferCapacity + initialSize);
1095     size_t readSize = fread(buffer.data() + initialSize, 1, buffer.size(), file);
1096     return readSize == buffer.size() - initialSize;
1097 }
1098
1099 static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1100 {
1101     FILE* f = fopen(fileName.utf8().data(), "rb");
1102     if (!f) {
1103         fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1104         return false;
1105     }
1106
1107     bool result = fillBufferWithContentsOfFile(f, buffer);
1108     fclose(f);
1109
1110     return result;
1111 }
1112
1113 static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1114 {
1115     if (!fillBufferWithContentsOfFile(fileName, buffer))
1116         return false;
1117     convertShebangToJSComment(buffer);
1118     return true;
1119 }
1120
1121 static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1122 {
1123     // We assume that fileName is always an absolute path.
1124 #if OS(WINDOWS)
1125     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
1126     // Use long UNC to pass the long path name to the Windows APIs.
1127     String longUNCPathName = WTF::makeString("\\\\?\\", fileName);
1128     static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
1129     auto utf16Vector = longUNCPathName.charactersWithNullTermination();
1130     FILE* f = _wfopen(reinterpret_cast<wchar_t*>(utf16Vector.data()), L"rb");
1131 #else
1132     FILE* f = fopen(fileName.utf8().data(), "r");
1133 #endif
1134     if (!f) {
1135         fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1136         return false;
1137     }
1138
1139     bool result = fillBufferWithContentsOfFile(f, buffer);
1140     if (result)
1141         convertShebangToJSComment(buffer);
1142     fclose(f);
1143
1144     return result;
1145 }
1146
1147 JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSValue)
1148 {
1149     VM& vm = globalObject->vm();
1150     auto scope = DECLARE_CATCH_SCOPE(vm);
1151     JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1152     String moduleKey = key.toWTFString(exec);
1153     if (UNLIKELY(scope.exception())) {
1154         JSValue exception = scope.exception();
1155         scope.clearException();
1156         return deferred->reject(exec, exception);
1157     }
1158
1159     // Here, now we consider moduleKey as the fileName.
1160     Vector<char> utf8;
1161     if (!fetchModuleFromLocalFileSystem(moduleKey, utf8))
1162         return deferred->reject(exec, createError(exec, makeString("Could not open file '", moduleKey, "'.")));
1163
1164     return deferred->resolve(exec, jsString(exec, stringFromUTF(utf8)));
1165 }
1166
1167
1168 static EncodedJSValue printInternal(ExecState* exec, FILE* out)
1169 {
1170     if (test262AsyncTest) {
1171         JSValue value = exec->argument(0);
1172         if (value.isString() && WTF::equal(asString(value)->value(exec).impl(), "Test262:AsyncTestComplete"))
1173             test262AsyncPassed = true;
1174         return JSValue::encode(jsUndefined());
1175     }
1176
1177     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1178         if (i)
1179             if (EOF == fputc(' ', out))
1180                 goto fail;
1181
1182         if (fprintf(out, "%s", exec->uncheckedArgument(i).toString(exec)->view(exec).get().utf8().data()) < 0)
1183             goto fail;
1184     }
1185
1186     fputc('\n', out);
1187 fail:
1188     fflush(out);
1189     return JSValue::encode(jsUndefined());
1190 }
1191
1192 EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState* exec) { return printInternal(exec, stdout); }
1193 EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState* exec) { return printInternal(exec, stderr); }
1194
1195 #ifndef NDEBUG
1196 EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
1197 {
1198     VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
1199     ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
1200     if (callerFrame)
1201         exec->vm().interpreter->dumpCallFrame(callerFrame);
1202     return JSValue::encode(jsUndefined());
1203 }
1204 #endif
1205
1206 EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
1207 {
1208     fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->view(exec).get().utf8().data());
1209     return JSValue::encode(jsUndefined());
1210 }
1211
1212 EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
1213 {
1214     if (exec->argumentCount() < 1)
1215         return JSValue::encode(jsUndefined());
1216     return JSValue::encode(jsString(exec, toString(exec->argument(0))));
1217 }
1218
1219 EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
1220 {
1221     if (exec->argumentCount() < 1)
1222         return JSValue::encode(jsUndefined());
1223     JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
1224     if (!object)
1225         return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
1226     return JSValue::encode(jsNontrivialString(exec, toString("<Butterfly: ", RawPointer(object->butterfly()), "; public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
1227 }
1228
1229 class FunctionJSCStackFunctor {
1230 public:
1231     FunctionJSCStackFunctor(StringBuilder& trace)
1232         : m_trace(trace)
1233     {
1234     }
1235
1236     StackVisitor::Status operator()(StackVisitor& visitor) const
1237     {
1238         m_trace.append(String::format("    %zu   %s\n", visitor->index(), visitor->toString().utf8().data()));
1239         return StackVisitor::Continue;
1240     }
1241
1242 private:
1243     StringBuilder& m_trace;
1244 };
1245
1246 EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
1247 {
1248     StringBuilder trace;
1249     trace.appendLiteral("--> Stack trace:\n");
1250
1251     FunctionJSCStackFunctor functor(trace);
1252     exec->iterate(functor);
1253     fprintf(stderr, "%s", trace.toString().utf8().data());
1254     return JSValue::encode(jsUndefined());
1255 }
1256
1257 EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
1258 {
1259     JSLockHolder lock(exec);
1260     return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
1261 }
1262
1263 EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
1264 {
1265     VM& vm = exec->vm();
1266     JSLockHolder lock(vm);
1267     auto scope = DECLARE_THROW_SCOPE(vm);
1268
1269     Root* root = jsDynamicCast<Root*>(exec->argument(0));
1270     if (!root)
1271         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Cannot create Element without a Root."))));
1272     return JSValue::encode(Element::create(vm, exec->lexicalGlobalObject(), root));
1273 }
1274
1275 EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
1276 {
1277     JSLockHolder lock(exec);
1278     Root* root = jsDynamicCast<Root*>(exec->argument(0));
1279     if (!root)
1280         return JSValue::encode(jsUndefined());
1281     Element* result = root->element();
1282     return JSValue::encode(result ? result : jsUndefined());
1283 }
1284
1285 EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
1286 {
1287     JSLockHolder lock(exec);
1288     Element* element = jsDynamicCast<Element*>(exec->argument(0));
1289     Root* root = jsDynamicCast<Root*>(exec->argument(1));
1290     if (element && root)
1291         element->setRoot(exec->vm(), root);
1292     return JSValue::encode(jsUndefined());
1293 }
1294
1295 EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec)
1296 {
1297     JSLockHolder lock(exec);
1298     return JSValue::encode(SimpleObject::create(exec->vm(), exec->lexicalGlobalObject()));
1299 }
1300
1301 EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec)
1302 {
1303     JSLockHolder lock(exec);
1304     SimpleObject* simpleObject = jsCast<SimpleObject*>(exec->argument(0).asCell());
1305     return JSValue::encode(simpleObject->hiddenValue());
1306 }
1307
1308 EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec)
1309 {
1310     JSLockHolder lock(exec);
1311     SimpleObject* simpleObject = jsCast<SimpleObject*>(exec->argument(0).asCell());
1312     JSValue value = exec->argument(1);
1313     simpleObject->setHiddenValue(exec->vm(), value);
1314     return JSValue::encode(jsUndefined());
1315 }
1316
1317 EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
1318 {
1319     JSLockHolder lock(exec);
1320     JSValue target = exec->argument(0);
1321     if (!target.isObject())
1322         return JSValue::encode(jsUndefined());
1323     JSObject* jsTarget = asObject(target.asCell());
1324     Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->getPrototypeDirect(), ImpureProxyType);
1325     JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
1326     return JSValue::encode(proxy);
1327 }
1328
1329 EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
1330 {
1331     JSLockHolder lock(exec);
1332     RuntimeArray* array = RuntimeArray::create(exec);
1333     return JSValue::encode(array);
1334 }
1335
1336 EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
1337 {
1338     JSLockHolder lock(exec);
1339     JSValue target = exec->argument(0);
1340     JSObject* delegate = nullptr;
1341     if (target.isObject())
1342         delegate = asObject(target.asCell());
1343     Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1344     ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
1345     return JSValue::encode(result);
1346 }
1347
1348 EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec)
1349 {
1350     JSLockHolder lock(exec);
1351     Structure* structure = CustomGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1352     CustomGetter* result = CustomGetter::create(exec->vm(), structure);
1353     return JSValue::encode(result);
1354 }
1355
1356 EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
1357 {
1358     JSLockHolder lock(exec);
1359     JSValue base = exec->argument(0);
1360     if (!base.isObject())
1361         return JSValue::encode(jsUndefined());
1362     JSValue delegate = exec->argument(1);
1363     if (!delegate.isObject())
1364         return JSValue::encode(jsUndefined());
1365     ImpureGetter* impureGetter = jsCast<ImpureGetter*>(asObject(base.asCell()));
1366     impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));
1367     return JSValue::encode(jsUndefined());
1368 }
1369
1370 EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
1371 {
1372     JSLockHolder lock(exec);
1373     exec->heap()->collectAllGarbage();
1374     return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1375 }
1376
1377 EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
1378 {
1379     JSLockHolder lock(exec);
1380     exec->heap()->collect(FullCollection);
1381     return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1382 }
1383
1384 EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
1385 {
1386     JSLockHolder lock(exec);
1387     exec->heap()->collect(EdenCollection);
1388     return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastEdenCollection()));
1389 }
1390
1391 EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*)
1392 {
1393     // It's best for this to be the first thing called in the 
1394     // JS program so the option is set to true before we JIT.
1395     Options::forceGCSlowPaths() = true;
1396     return JSValue::encode(jsUndefined());
1397 }
1398
1399 EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
1400 {
1401     JSLockHolder lock(exec);
1402     return JSValue::encode(jsNumber(exec->heap()->size()));
1403 }
1404
1405 // This function is not generally very helpful in 64-bit code as the tag and payload
1406 // share a register. But in 32-bit JITed code the tag may not be checked if an
1407 // optimization removes type checking requirements, such as in ===.
1408 EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState* exec)
1409 {
1410     JSValue value = exec->argument(0);
1411     if (!value.isCell())
1412         return JSValue::encode(jsUndefined());
1413     // Need to cast to uint64_t so bitwise_cast will play along.
1414     uint64_t asNumber = reinterpret_cast<uint64_t>(value.asCell());
1415     EncodedJSValue returnValue = JSValue::encode(jsNumber(bitwise_cast<double>(asNumber)));
1416     return returnValue;
1417 }
1418
1419 static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState* exec)
1420 {
1421     JSValue value = exec->argument(0);
1422     if (!value.isObject())
1423         return JSValue::encode(jsUndefined());
1424
1425     JSValue property = exec->argument(1);
1426     if (!property.isString())
1427         return JSValue::encode(jsUndefined());
1428
1429     Identifier ident = Identifier::fromString(&exec->vm(), property.toWTFString(exec));
1430
1431     PropertySlot slot(value, PropertySlot::InternalMethodType::VMInquiry);
1432     value.getPropertySlot(exec, ident, slot);
1433
1434     JSValue result;
1435     if (slot.isCacheableGetter())
1436         result = slot.getterSetter();
1437     else
1438         result = jsNull();
1439
1440     return JSValue::encode(result);
1441 }
1442
1443 EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
1444 {
1445     // We need this function for compatibility with the Mozilla JS tests but for now
1446     // we don't actually do any version-specific handling
1447     return JSValue::encode(jsUndefined());
1448 }
1449
1450 EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
1451 {
1452     VM& vm = exec->vm();
1453     auto scope = DECLARE_THROW_SCOPE(vm);
1454
1455     String fileName = exec->argument(0).toWTFString(exec);
1456     if (UNLIKELY(scope.exception()))
1457         return JSValue::encode(jsUndefined());
1458     Vector<char> script;
1459     if (!fetchScriptFromLocalFileSystem(fileName, script))
1460         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
1461
1462     GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
1463
1464     JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
1465     for (unsigned i = 1; i < exec->argumentCount(); ++i)
1466         array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
1467     globalObject->putDirect(
1468         vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
1469
1470     NakedPtr<Exception> exception;
1471     StopWatch stopWatch;
1472     stopWatch.start();
1473     evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), exception);
1474     stopWatch.stop();
1475
1476     if (exception) {
1477         throwException(globalObject->globalExec(), scope, exception);
1478         return JSValue::encode(jsUndefined());
1479     }
1480     
1481     return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
1482 }
1483
1484 EncodedJSValue JSC_HOST_CALL functionRunString(ExecState* exec)
1485 {
1486     VM& vm = exec->vm();
1487     auto scope = DECLARE_THROW_SCOPE(vm);
1488
1489     String source = exec->argument(0).toWTFString(exec);
1490     if (UNLIKELY(scope.exception()))
1491         return JSValue::encode(jsUndefined());
1492
1493     GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
1494
1495     JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
1496     for (unsigned i = 1; i < exec->argumentCount(); ++i)
1497         array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
1498     globalObject->putDirect(
1499         vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
1500
1501     NakedPtr<Exception> exception;
1502     evaluate(globalObject->globalExec(), makeSource(source), JSValue(), exception);
1503
1504     if (exception) {
1505         scope.throwException(globalObject->globalExec(), exception);
1506         return JSValue::encode(jsUndefined());
1507     }
1508     
1509     return JSValue::encode(globalObject);
1510 }
1511
1512 EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
1513 {
1514     VM& vm = exec->vm();
1515     auto scope = DECLARE_THROW_SCOPE(vm);
1516
1517     String fileName = exec->argument(0).toWTFString(exec);
1518     if (UNLIKELY(scope.exception()))
1519         return JSValue::encode(jsUndefined());
1520     Vector<char> script;
1521     if (!fetchScriptFromLocalFileSystem(fileName, script))
1522         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
1523
1524     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1525     
1526     NakedPtr<Exception> evaluationException;
1527     JSValue result = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), evaluationException);
1528     if (evaluationException)
1529         throwException(exec, scope, evaluationException);
1530     return JSValue::encode(result);
1531 }
1532
1533 EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState* exec)
1534 {
1535     VM& vm = exec->vm();
1536     auto scope = DECLARE_THROW_SCOPE(vm);
1537
1538     String sourceCode = exec->argument(0).toWTFString(exec);
1539     if (UNLIKELY(scope.exception()))
1540         return JSValue::encode(jsUndefined());
1541     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1542
1543     NakedPtr<Exception> evaluationException;
1544     JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode), JSValue(), evaluationException);
1545     if (evaluationException)
1546         throwException(exec, scope, evaluationException);
1547     return JSValue::encode(result);
1548 }
1549
1550 EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
1551 {
1552     VM& vm = exec->vm();
1553     auto scope = DECLARE_THROW_SCOPE(vm);
1554
1555     String fileName = exec->argument(0).toWTFString(exec);
1556     if (UNLIKELY(scope.exception()))
1557         return JSValue::encode(jsUndefined());
1558     Vector<char> script;
1559     if (!fillBufferWithContentsOfFile(fileName, script))
1560         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
1561
1562     return JSValue::encode(jsString(exec, stringFromUTF(script)));
1563 }
1564
1565 EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
1566 {
1567     VM& vm = exec->vm();
1568     auto scope = DECLARE_THROW_SCOPE(vm);
1569
1570     String fileName = exec->argument(0).toWTFString(exec);
1571     if (UNLIKELY(scope.exception()))
1572         return JSValue::encode(jsUndefined());
1573     Vector<char> script;
1574     if (!fetchScriptFromLocalFileSystem(fileName, script))
1575         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
1576
1577     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1578
1579     StopWatch stopWatch;
1580     stopWatch.start();
1581
1582     JSValue syntaxException;
1583     bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, fileName), &syntaxException);
1584     stopWatch.stop();
1585
1586     if (!validSyntax)
1587         throwException(exec, scope, syntaxException);
1588     return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
1589 }
1590
1591 #if ENABLE(SAMPLING_FLAGS)
1592 EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
1593 {
1594     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1595         unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
1596         if ((flag >= 1) && (flag <= 32))
1597             SamplingFlags::setFlag(flag);
1598     }
1599     return JSValue::encode(jsNull());
1600 }
1601
1602 EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
1603 {
1604     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1605         unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
1606         if ((flag >= 1) && (flag <= 32))
1607             SamplingFlags::clearFlag(flag);
1608     }
1609     return JSValue::encode(jsNull());
1610 }
1611 #endif
1612
1613 EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState* exec)
1614 {
1615     return JSValue::encode(exec->vm().shadowChicken().functionsOnStack(exec));
1616 }
1617
1618 EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState* exec)
1619 {
1620     exec->vm().setGlobalConstRedeclarationShouldThrow(false);
1621     return JSValue::encode(jsUndefined());
1622 }
1623
1624 EncodedJSValue JSC_HOST_CALL functionGetRandomSeed(ExecState* exec)
1625 {
1626     return JSValue::encode(jsNumber(exec->lexicalGlobalObject()->weakRandom().seed()));
1627 }
1628
1629 EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState* exec)
1630 {
1631     VM& vm = exec->vm();
1632     auto scope = DECLARE_THROW_SCOPE(vm);
1633
1634     unsigned seed = exec->argument(0).toUInt32(exec);
1635     if (UNLIKELY(scope.exception()))
1636         return JSValue::encode(jsUndefined());
1637     exec->lexicalGlobalObject()->weakRandom().setSeed(seed);
1638     return JSValue::encode(jsUndefined());
1639 }
1640
1641 EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
1642 {
1643     Vector<char, 256> line;
1644     int c;
1645     while ((c = getchar()) != EOF) {
1646         // FIXME: Should we also break on \r? 
1647         if (c == '\n')
1648             break;
1649         line.append(c);
1650     }
1651     line.append('\0');
1652     return JSValue::encode(jsString(exec, line.data()));
1653 }
1654
1655 EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
1656 {
1657     return JSValue::encode(jsNumber(currentTime()));
1658 }
1659
1660 EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
1661 {
1662     return JSValue::encode(setNeverInline(exec));
1663 }
1664
1665 EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState* exec)
1666 {
1667     return JSValue::encode(setNeverOptimize(exec));
1668 }
1669
1670 EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState* exec)
1671 {
1672     if (JSFunction* function = jsDynamicCast<JSFunction*>(exec->argument(0))) {
1673         FunctionExecutable* executable = function->jsExecutable();
1674         executable->setNeverFTLOptimize(true);
1675     }
1676
1677     return JSValue::encode(jsUndefined());
1678 }
1679
1680 EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState* exec)
1681 {
1682     return JSValue::encode(setCannotUseOSRExitFuzzing(exec));
1683 }
1684
1685 EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
1686 {
1687     return JSValue::encode(optimizeNextInvocation(exec));
1688 }
1689
1690 EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
1691 {
1692     return JSValue::encode(numberOfDFGCompiles(exec));
1693 }
1694
1695 EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1696 {
1697     if (exec->argumentCount() < 1)
1698         return JSValue::encode(jsUndefined());
1699     
1700     CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1701     if (!block)
1702         return JSValue::encode(jsNumber(0));
1703     
1704     return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1705 }
1706
1707 EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1708 {
1709     VM& vm = exec->vm();
1710     auto scope = DECLARE_THROW_SCOPE(vm);
1711
1712     if (exec->argumentCount() < 1)
1713         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Not enough arguments"))));
1714     
1715     JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1716     if (!buffer)
1717         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected an array buffer"))));
1718     
1719     ArrayBufferContents dummyContents;
1720     buffer->impl()->transfer(dummyContents);
1721     
1722     return JSValue::encode(jsUndefined());
1723 }
1724
1725 EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState* exec)
1726 {
1727     exec->vm().setFailNextNewCodeBlock();
1728     return JSValue::encode(jsUndefined());
1729 }
1730
1731 EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1732 {
1733     jscExit(EXIT_SUCCESS);
1734
1735 #if COMPILER(MSVC)
1736     // Without this, Visual Studio will complain that this method does not return a value.
1737     return JSValue::encode(jsUndefined());
1738 #endif
1739 }
1740
1741 EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*)
1742 {
1743     CRASH();
1744 }
1745
1746 EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1747 EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1748
1749 EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1750 EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1751 EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
1752 {
1753     for (size_t i = 0; i < exec->argumentCount(); ++i) {
1754         if (!exec->argument(i).isInt32())
1755             return JSValue::encode(jsBoolean(false));
1756     }
1757     return JSValue::encode(jsBoolean(true));
1758 }
1759
1760 EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1761
1762 EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1763 {
1764     return JSValue::encode(jsNumber(42));
1765 }
1766
1767 EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1768 {
1769     return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1770 }
1771
1772 EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1773 {
1774     JSValue value = exec->argument(0);
1775     if (value.isObject())
1776         return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1777     return JSValue::encode(jsBoolean(false));
1778 }
1779
1780 EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1781 {
1782     exec->vm().dumpTypeProfilerData();
1783     return JSValue::encode(jsUndefined());
1784 }
1785
1786 EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
1787 {
1788     RELEASE_ASSERT(exec->vm().typeProfiler());
1789     exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
1790
1791     JSValue functionValue = exec->argument(0);
1792     RELEASE_ASSERT(functionValue.isFunction());
1793     FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1794
1795     RELEASE_ASSERT(exec->argument(1).isString());
1796     String substring = exec->argument(1).getString(exec);
1797     String sourceCodeText = executable->source().view().toString();
1798     unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
1799     
1800     String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
1801     return JSValue::encode(JSONParse(exec, jsonString));
1802 }
1803
1804 EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
1805 {
1806     RELEASE_ASSERT(exec->vm().typeProfiler());
1807     exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
1808
1809     JSValue functionValue = exec->argument(0);
1810     RELEASE_ASSERT(functionValue.isFunction());
1811     FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1812
1813     unsigned offset = executable->typeProfilingStartOffset();
1814     String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
1815     return JSValue::encode(JSONParse(exec, jsonString));
1816 }
1817
1818 EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
1819 {
1820     RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1821     exec->vm().controlFlowProfiler()->dumpData();
1822     return JSValue::encode(jsUndefined());
1823 }
1824
1825 EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
1826 {
1827     RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1828
1829     JSValue functionValue = exec->argument(0);
1830     RELEASE_ASSERT(functionValue.isFunction());
1831     FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1832
1833     RELEASE_ASSERT(exec->argument(1).isString());
1834     String substring = exec->argument(1).getString(exec);
1835     String sourceCodeText = executable->source().view().toString();
1836     RELEASE_ASSERT(sourceCodeText.contains(substring));
1837     int offset = sourceCodeText.find(substring) + executable->source().startOffset();
1838     
1839     bool hasExecuted = exec->vm().controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), exec->vm());
1840     return JSValue::encode(jsBoolean(hasExecuted));
1841 }
1842
1843 EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec)
1844 {
1845     RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1846
1847     JSValue functionValue = exec->argument(0);
1848     RELEASE_ASSERT(functionValue.isFunction());
1849     FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1850
1851     RELEASE_ASSERT(exec->argument(1).isString());
1852     String substring = exec->argument(1).getString(exec);
1853     String sourceCodeText = executable->source().view().toString();
1854     RELEASE_ASSERT(sourceCodeText.contains(substring));
1855     int offset = sourceCodeText.find(substring) + executable->source().startOffset();
1856     
1857     size_t executionCount = exec->vm().controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), exec->vm());
1858     return JSValue::encode(JSValue(executionCount));
1859 }
1860
1861 EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
1862 {
1863     Options::useExceptionFuzz() = true;
1864     return JSValue::encode(jsUndefined());
1865 }
1866
1867 EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState* exec)
1868 {
1869     exec->vm().drainMicrotasks();
1870     return JSValue::encode(jsUndefined());
1871 }
1872
1873 EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*)
1874 {
1875 #if USE(JSVALUE64)
1876     return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
1877 #else
1878     return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
1879 #endif
1880 }
1881
1882 EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
1883 {
1884     VM& vm = exec->vm();
1885     auto scope = DECLARE_THROW_SCOPE(vm);
1886
1887     String fileName = exec->argument(0).toWTFString(exec);
1888     if (UNLIKELY(scope.exception()))
1889         return JSValue::encode(jsUndefined());
1890     Vector<char> script;
1891     if (!fetchScriptFromLocalFileSystem(fileName, script))
1892         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
1893
1894     JSInternalPromise* promise = loadAndEvaluateModule(exec, fileName);
1895     if (UNLIKELY(scope.exception()))
1896         return JSValue::encode(jsUndefined());
1897
1898     JSValue error;
1899     JSFunction* errorHandler = JSNativeStdFunction::create(vm, exec->lexicalGlobalObject(), 1, String(), [&](ExecState* exec) {
1900         error = exec->argument(0);
1901         return JSValue::encode(jsUndefined());
1902     });
1903
1904     promise->then(exec, nullptr, errorHandler);
1905     vm.drainMicrotasks();
1906     if (error)
1907         return JSValue::encode(throwException(exec, scope, error));
1908     return JSValue::encode(jsUndefined());
1909 }
1910
1911 EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState* exec)
1912 {
1913     VM& vm = exec->vm();
1914     auto scope = DECLARE_THROW_SCOPE(vm);
1915
1916     if (exec->argumentCount() < 1 || !exec->argument(0).isString())
1917         return JSValue::encode(jsUndefined());
1918
1919     String functionText = exec->argument(0).toWTFString(exec);
1920     if (UNLIKELY(scope.exception()))
1921         return JSValue::encode(JSValue());
1922
1923     const SourceCode& source = makeSource(functionText);
1924     JSFunction* func = JSFunction::createBuiltinFunction(vm, createBuiltinExecutable(vm, source, Identifier::fromString(&vm, "foo"), ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, source), exec->lexicalGlobalObject());
1925
1926     return JSValue::encode(func);
1927 }
1928
1929 EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
1930 {
1931     VM& vm = exec->vm();
1932     return JSValue::encode(GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>()));
1933 }
1934
1935 EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState* exec)
1936 {
1937     VM& vm = exec->vm();
1938     auto scope = DECLARE_THROW_SCOPE(vm);
1939
1940     String source = exec->argument(0).toWTFString(exec);
1941     if (UNLIKELY(scope.exception()))
1942         return JSValue::encode(jsUndefined());
1943
1944     StopWatch stopWatch;
1945     stopWatch.start();
1946
1947     ParserError error;
1948     bool validSyntax = checkModuleSyntax(exec, makeSource(source), error);
1949     stopWatch.stop();
1950
1951     if (!validSyntax)
1952         throwException(exec, scope, jsNontrivialString(exec, toString("SyntaxError: ", error.message(), ":", error.line())));
1953     return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
1954 }
1955
1956 EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*)
1957 {
1958 #if ENABLE(SAMPLING_PROFILER)
1959     return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
1960 #else
1961     return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
1962 #endif
1963 }
1964
1965 EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState* exec)
1966 {
1967     VM& vm = exec->vm();
1968     JSLockHolder lock(vm);
1969     auto scope = DECLARE_THROW_SCOPE(vm);
1970
1971     HeapSnapshotBuilder snapshotBuilder(exec->vm().ensureHeapProfiler());
1972     snapshotBuilder.buildSnapshot();
1973
1974     String jsonString = snapshotBuilder.json();
1975     EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
1976     RELEASE_ASSERT(!scope.exception());
1977     return result;
1978 }
1979
1980 EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*)
1981 {
1982     resetSuperSamplerState();
1983     return JSValue::encode(jsUndefined());
1984 }
1985
1986 EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState* exec)
1987 {
1988     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1989         if (JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0)))
1990             object->ensureArrayStorage(exec->vm());
1991     }
1992     return JSValue::encode(jsUndefined());
1993 }
1994
1995 #if ENABLE(SAMPLING_PROFILER)
1996 EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState* exec)
1997 {
1998     SamplingProfiler& samplingProfiler = exec->vm().ensureSamplingProfiler(WTF::Stopwatch::create());
1999     samplingProfiler.noticeCurrentThreadAsJSCExecutionThread();
2000     samplingProfiler.start();
2001     return JSValue::encode(jsUndefined());
2002 }
2003
2004 EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState* exec)
2005 {
2006     VM& vm = exec->vm();
2007     auto scope = DECLARE_THROW_SCOPE(vm);
2008
2009     if (!vm.samplingProfiler())
2010         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Sampling profiler was never started"))));
2011
2012     String jsonString = vm.samplingProfiler()->stackTracesAsJSON();
2013     EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
2014     RELEASE_ASSERT(!scope.exception());
2015     return result;
2016 }
2017 #endif // ENABLE(SAMPLING_PROFILER)
2018
2019 // Use SEH for Release builds only to get rid of the crash report dialog
2020 // (luckily the same tests fail in Release and Debug builds so far). Need to
2021 // be in a separate main function because the jscmain function requires object
2022 // unwinding.
2023
2024 #if COMPILER(MSVC) && !defined(_DEBUG)
2025 #define TRY       __try {
2026 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
2027 #else
2028 #define TRY
2029 #define EXCEPT(x)
2030 #endif
2031
2032 int jscmain(int argc, char** argv);
2033
2034 static double s_desiredTimeout;
2035
2036 static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
2037 {
2038     auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
2039     std::this_thread::sleep_for(timeout);
2040     
2041     dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
2042     CRASH();
2043 }
2044
2045 int main(int argc, char** argv)
2046 {
2047 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
2048     // Enabled IEEE754 denormal support.
2049     fenv_t env;
2050     fegetenv( &env );
2051     env.__fpscr &= ~0x01000000u;
2052     fesetenv( &env );
2053 #endif
2054
2055 #if OS(WINDOWS)
2056     // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
2057     // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
2058     // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
2059     ::SetErrorMode(0);
2060
2061 #if defined(_DEBUG)
2062     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
2063     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2064     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
2065     _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
2066     _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
2067     _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
2068 #endif
2069
2070     timeBeginPeriod(1);
2071 #endif
2072
2073 #if PLATFORM(EFL)
2074     ecore_init();
2075 #endif
2076
2077 #if PLATFORM(GTK)
2078     if (!setlocale(LC_ALL, ""))
2079         WTFLogAlways("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
2080 #endif
2081
2082     // Need to initialize WTF threading before we start any threads. Cannot initialize JSC
2083     // threading yet, since that would do somethings that we'd like to defer until after we
2084     // have a chance to parse options.
2085     WTF::initializeThreading();
2086
2087     if (char* timeoutString = getenv("JSCTEST_timeout")) {
2088         if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
2089             dataLog(
2090                 "WARNING: timeout string is malformed, got ", timeoutString,
2091                 " but expected a number. Not using a timeout.\n");
2092         } else
2093             createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
2094     }
2095
2096 #if PLATFORM(IOS)
2097     Options::crashIfCantAllocateJITMemory() = true;
2098 #endif
2099
2100     // We can't use destructors in the following code because it uses Windows
2101     // Structured Exception Handling
2102     int res = 0;
2103     TRY
2104         res = jscmain(argc, argv);
2105     EXCEPT(res = 3)
2106     finalizeStatsAtEndOfTesting();
2107
2108 #if PLATFORM(EFL)
2109     ecore_shutdown();
2110 #endif
2111
2112     jscExit(res);
2113 }
2114
2115 static void dumpException(GlobalObject* globalObject, JSValue exception)
2116 {
2117     VM& vm = globalObject->vm();
2118     auto scope = DECLARE_CATCH_SCOPE(vm);
2119
2120 #define CHECK_EXCEPTION() do { \
2121         if (scope.exception()) { \
2122             scope.clearException(); \
2123             return; \
2124         } \
2125     } while (false)
2126
2127     printf("Exception: %s\n", exception.toWTFString(globalObject->globalExec()).utf8().data());
2128
2129     Identifier nameID = Identifier::fromString(globalObject->globalExec(), "name");
2130     Identifier fileNameID = Identifier::fromString(globalObject->globalExec(), "sourceURL");
2131     Identifier lineNumberID = Identifier::fromString(globalObject->globalExec(), "line");
2132     Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
2133     
2134     JSValue nameValue = exception.get(globalObject->globalExec(), nameID);
2135     CHECK_EXCEPTION();
2136     JSValue fileNameValue = exception.get(globalObject->globalExec(), fileNameID);
2137     CHECK_EXCEPTION();
2138     JSValue lineNumberValue = exception.get(globalObject->globalExec(), lineNumberID);
2139     CHECK_EXCEPTION();
2140     JSValue stackValue = exception.get(globalObject->globalExec(), stackID);
2141     CHECK_EXCEPTION();
2142     
2143     if (nameValue.toWTFString(globalObject->globalExec()) == "SyntaxError"
2144         && (!fileNameValue.isUndefinedOrNull() || !lineNumberValue.isUndefinedOrNull())) {
2145         printf(
2146             "at %s:%s\n",
2147             fileNameValue.toWTFString(globalObject->globalExec()).utf8().data(),
2148             lineNumberValue.toWTFString(globalObject->globalExec()).utf8().data());
2149     }
2150     
2151     if (!stackValue.isUndefinedOrNull())
2152         printf("%s\n", stackValue.toWTFString(globalObject->globalExec()).utf8().data());
2153
2154 #undef CHECK_EXCEPTION
2155 }
2156
2157 static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue exception, const String& expectedExceptionName, bool alwaysDumpException)
2158 {
2159     auto scope = DECLARE_CATCH_SCOPE(vm);
2160     scope.clearException();
2161     if (!exception) {
2162         printf("Expected uncaught exception with name '%s' but none was thrown\n", expectedExceptionName.utf8().data());
2163         return false;
2164     }
2165
2166     ExecState* exec = globalObject->globalExec();
2167     JSValue exceptionClass = globalObject->get(exec, Identifier::fromString(exec, expectedExceptionName));
2168     if (!exceptionClass.isObject() || scope.exception()) {
2169         printf("Expected uncaught exception with name '%s' but given exception class is not defined\n", expectedExceptionName.utf8().data());
2170         return false;
2171     }
2172
2173     bool isInstanceOfExpectedException = jsCast<JSObject*>(exceptionClass)->hasInstance(exec, exception);
2174     if (scope.exception()) {
2175         printf("Expected uncaught exception with name '%s' but given exception class fails performing hasInstance\n", expectedExceptionName.utf8().data());
2176         return false;
2177     }
2178     if (isInstanceOfExpectedException) {
2179         if (alwaysDumpException)
2180             dumpException(globalObject, exception);
2181         return true;
2182     }
2183
2184     printf("Expected uncaught exception with name '%s' but exception value is not instance of this exception class\n", expectedExceptionName.utf8().data());
2185     dumpException(globalObject, exception);
2186     return false;
2187 }
2188
2189 static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool module)
2190 {
2191     String fileName;
2192     Vector<char> scriptBuffer;
2193
2194     if (dump)
2195         JSC::Options::dumpGeneratedBytecodes() = true;
2196
2197     VM& vm = globalObject->vm();
2198     auto scope = DECLARE_CATCH_SCOPE(vm);
2199     bool success = true;
2200
2201     auto checkException = [&] (bool isLastFile, bool hasException, JSValue value) {
2202         if (!uncaughtExceptionName || !isLastFile) {
2203             success = success && !hasException;
2204             if (dump && !hasException)
2205                 printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
2206             if (hasException)
2207                 dumpException(globalObject, value);
2208         } else
2209             success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
2210     };
2211
2212 #if ENABLE(SAMPLING_FLAGS)
2213     SamplingFlags::start();
2214 #endif
2215
2216     for (size_t i = 0; i < scripts.size(); i++) {
2217         JSInternalPromise* promise = nullptr;
2218         bool isModule = module || scripts[i].scriptType == Script::ScriptType::Module;
2219         if (scripts[i].codeSource == Script::CodeSource::File) {
2220             fileName = scripts[i].argument;
2221             if (scripts[i].strictMode == Script::StrictMode::Strict)
2222                 scriptBuffer.append("\"use strict\";\n", strlen("\"use strict\";\n"));
2223
2224             if (isModule)
2225                 promise = loadAndEvaluateModule(globalObject->globalExec(), fileName);
2226             else {
2227                 if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer))
2228                     return false; // fail early so we can catch missing files
2229             }
2230         } else {
2231             size_t commandLineLength = strlen(scripts[i].argument);
2232             scriptBuffer.resize(commandLineLength);
2233             std::copy(scripts[i].argument, scripts[i].argument + commandLineLength, scriptBuffer.begin());
2234             fileName = ASCIILiteral("[Command Line]");
2235         }
2236
2237         bool isLastFile = i == scripts.size() - 1;
2238         if (isModule) {
2239             if (!promise)
2240                 promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
2241             scope.clearException();
2242
2243             JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
2244                 checkException(isLastFile, false, exec->argument(0));
2245                 return JSValue::encode(jsUndefined());
2246             });
2247
2248             JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
2249                 checkException(isLastFile, true, exec->argument(0));
2250                 return JSValue::encode(jsUndefined());
2251             });
2252
2253             promise->then(globalObject->globalExec(), fulfillHandler, rejectHandler);
2254             vm.drainMicrotasks();
2255         } else {
2256             NakedPtr<Exception> evaluationException;
2257             JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, fileName), JSValue(), evaluationException);
2258             ASSERT(!scope.exception());
2259             if (evaluationException)
2260                 returnValue = evaluationException->value();
2261             checkException(isLastFile, evaluationException, returnValue);
2262         }
2263
2264         scriptBuffer.clear();
2265         scope.clearException();
2266     }
2267
2268 #if ENABLE(REGEXP_TRACING)
2269     vm.dumpRegExpTrace();
2270 #endif
2271     return success;
2272 }
2273
2274 #define RUNNING_FROM_XCODE 0
2275
2276 static void runInteractive(GlobalObject* globalObject)
2277 {
2278     VM& vm = globalObject->vm();
2279     auto scope = DECLARE_CATCH_SCOPE(vm);
2280
2281     String interpreterName(ASCIILiteral("Interpreter"));
2282     
2283     bool shouldQuit = false;
2284     while (!shouldQuit) {
2285 #if HAVE(READLINE) && !RUNNING_FROM_XCODE
2286         ParserError error;
2287         String source;
2288         do {
2289             error = ParserError();
2290             char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
2291             shouldQuit = !line;
2292             if (!line)
2293                 break;
2294             source = source + line;
2295             source = source + '\n';
2296             checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
2297             if (!line[0])
2298                 break;
2299             add_history(line);
2300         } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable);
2301         
2302         if (error.isValid()) {
2303             printf("%s:%d\n", error.message().utf8().data(), error.line());
2304             continue;
2305         }
2306         
2307         
2308         NakedPtr<Exception> evaluationException;
2309         JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), evaluationException);
2310 #else
2311         printf("%s", interactivePrompt);
2312         Vector<char, 256> line;
2313         int c;
2314         while ((c = getchar()) != EOF) {
2315             // FIXME: Should we also break on \r? 
2316             if (c == '\n')
2317                 break;
2318             line.append(c);
2319         }
2320         if (line.isEmpty())
2321             break;
2322
2323         NakedPtr<Exception> evaluationException;
2324         JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, interpreterName), JSValue(), evaluationException);
2325 #endif
2326         if (evaluationException)
2327             printf("Exception: %s\n", evaluationException->value().toWTFString(globalObject->globalExec()).utf8().data());
2328         else
2329             printf("%s\n", returnValue.toWTFString(globalObject->globalExec()).utf8().data());
2330
2331         scope.clearException();
2332         globalObject->vm().drainMicrotasks();
2333     }
2334     printf("\n");
2335 }
2336
2337 static NO_RETURN void printUsageStatement(bool help = false)
2338 {
2339     fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
2340     fprintf(stderr, "  -d         Dumps bytecode (debug builds only)\n");
2341     fprintf(stderr, "  -e         Evaluate argument as script code\n");
2342     fprintf(stderr, "  -f         Specifies a source file (deprecated)\n");
2343     fprintf(stderr, "  -h|--help  Prints this help message\n");
2344     fprintf(stderr, "  -i         Enables interactive mode (default if no files are specified)\n");
2345     fprintf(stderr, "  -m         Execute as a module\n");
2346 #if HAVE(SIGNAL_H)
2347     fprintf(stderr, "  -s         Installs signal handlers that exit on a crash (Unix platforms only)\n");
2348 #endif
2349     fprintf(stderr, "  -p <file>  Outputs profiling data to a file\n");
2350     fprintf(stderr, "  -x         Output exit code before terminating\n");
2351     fprintf(stderr, "\n");
2352     fprintf(stderr, "  --sample                   Collects and outputs sampling profiler data\n");
2353     fprintf(stderr, "  --test262-async            Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n");
2354     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");
2355     fprintf(stderr, "  --module-file=<file>       Parse and evaluate the given file as module (this option may be passed more than once)\n");
2356     fprintf(stderr, "  --exception=<name>         Check the last script exits with an uncaught exception with the specified name\n");
2357     fprintf(stderr, "  --dumpException            Dump uncaught exception text\n");
2358     fprintf(stderr, "  --options                  Dumps all JSC VM options and exits\n");
2359     fprintf(stderr, "  --dumpOptions              Dumps all non-default JSC VM options before continuing\n");
2360     fprintf(stderr, "  --<jsc VM option>=<value>  Sets the specified JSC VM option\n");
2361     fprintf(stderr, "\n");
2362
2363     jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
2364 }
2365
2366 void CommandLine::parseArguments(int argc, char** argv)
2367 {
2368     Options::initialize();
2369     
2370     int i = 1;
2371     JSC::Options::DumpLevel dumpOptionsLevel = JSC::Options::DumpLevel::None;
2372     bool needToExit = false;
2373
2374     bool hasBadJSCOptions = false;
2375     for (; i < argc; ++i) {
2376         const char* arg = argv[i];
2377         if (!strcmp(arg, "-f")) {
2378             if (++i == argc)
2379                 printUsageStatement();
2380             m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
2381             continue;
2382         }
2383         if (!strcmp(arg, "-e")) {
2384             if (++i == argc)
2385                 printUsageStatement();
2386             m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::CommandLine, Script::ScriptType::Script, argv[i]));
2387             continue;
2388         }
2389         if (!strcmp(arg, "-i")) {
2390             m_interactive = true;
2391             continue;
2392         }
2393         if (!strcmp(arg, "-d")) {
2394             m_dump = true;
2395             continue;
2396         }
2397         if (!strcmp(arg, "-p")) {
2398             if (++i == argc)
2399                 printUsageStatement();
2400             m_profile = true;
2401             m_profilerOutput = argv[i];
2402             continue;
2403         }
2404         if (!strcmp(arg, "-m")) {
2405             m_module = true;
2406             continue;
2407         }
2408         if (!strcmp(arg, "-s")) {
2409 #if HAVE(SIGNAL_H)
2410             signal(SIGILL, _exit);
2411             signal(SIGFPE, _exit);
2412             signal(SIGBUS, _exit);
2413             signal(SIGSEGV, _exit);
2414 #endif
2415             continue;
2416         }
2417         if (!strcmp(arg, "-x")) {
2418             m_exitCode = true;
2419             continue;
2420         }
2421         if (!strcmp(arg, "--")) {
2422             ++i;
2423             break;
2424         }
2425         if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
2426             printUsageStatement(true);
2427
2428         if (!strcmp(arg, "--options")) {
2429             dumpOptionsLevel = JSC::Options::DumpLevel::Verbose;
2430             needToExit = true;
2431             continue;
2432         }
2433         if (!strcmp(arg, "--dumpOptions")) {
2434             dumpOptionsLevel = JSC::Options::DumpLevel::Overridden;
2435             continue;
2436         }
2437         if (!strcmp(arg, "--sample")) {
2438             JSC::Options::useSamplingProfiler() = true;
2439             JSC::Options::collectSamplingProfilerDataForJSCShell() = true;
2440             m_dumpSamplingProfilerData = true;
2441             continue;
2442         }
2443
2444         if (!strcmp(arg, "--test262-async")) {
2445             test262AsyncTest = true;
2446             continue;
2447         }
2448
2449         static const unsigned strictFileStrLength = strlen("--strict-file=");
2450         if (!strncmp(arg, "--strict-file=", strictFileStrLength)) {
2451             m_scripts.append(Script(Script::StrictMode::Strict, Script::CodeSource::File, Script::ScriptType::Script, argv[i] + strictFileStrLength));
2452             continue;
2453         }
2454
2455         static const unsigned moduleFileStrLength = strlen("--module-file=");
2456         if (!strncmp(arg, "--module-file=", moduleFileStrLength)) {
2457             m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Module, argv[i] + moduleFileStrLength));
2458             continue;
2459         }
2460
2461         if (!strcmp(arg, "--dumpException")) {
2462             m_alwaysDumpUncaughtException = true;
2463             continue;
2464         }
2465
2466         static const unsigned exceptionStrLength = strlen("--exception=");
2467         if (!strncmp(arg, "--exception=", exceptionStrLength)) {
2468             m_uncaughtExceptionName = String(arg + exceptionStrLength);
2469             continue;
2470         }
2471
2472         // See if the -- option is a JSC VM option.
2473         if (strstr(arg, "--") == arg) {
2474             if (!JSC::Options::setOption(&arg[2])) {
2475                 hasBadJSCOptions = true;
2476                 dataLog("ERROR: invalid option: ", arg, "\n");
2477             }
2478             continue;
2479         }
2480
2481         // This arg is not recognized by the VM nor by jsc. Pass it on to the
2482         // script.
2483         m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
2484     }
2485
2486     if (hasBadJSCOptions && JSC::Options::validateOptions())
2487         CRASH();
2488
2489     if (m_scripts.isEmpty())
2490         m_interactive = true;
2491
2492     for (; i < argc; ++i)
2493         m_arguments.append(argv[i]);
2494
2495     if (dumpOptionsLevel != JSC::Options::DumpLevel::None) {
2496         const char* optionsTitle = (dumpOptionsLevel == JSC::Options::DumpLevel::Overridden)
2497             ? "Modified JSC runtime options:"
2498             : "All JSC runtime options:";
2499         JSC::Options::dumpAllOptions(stderr, dumpOptionsLevel, optionsTitle);
2500     }
2501     JSC::Options::ensureOptionsAreCoherent();
2502     if (needToExit)
2503         jscExit(EXIT_SUCCESS);
2504 }
2505
2506 // We make this function no inline so that globalObject won't be on the stack if we do a GC in jscmain.
2507 static int NEVER_INLINE runJSC(VM* vm, CommandLine options)
2508 {
2509     JSLockHolder locker(vm);
2510
2511     int result;
2512     if (options.m_profile && !vm->m_perBytecodeProfiler)
2513         vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
2514
2515     GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
2516     bool success = runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
2517     if (options.m_interactive && success)
2518         runInteractive(globalObject);
2519
2520     vm->drainMicrotasks();
2521     result = success && (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
2522
2523     if (options.m_exitCode)
2524         printf("jsc exiting %d\n", result);
2525
2526     if (options.m_profile) {
2527         if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
2528             fprintf(stderr, "could not save profiler output.\n");
2529     }
2530
2531 #if ENABLE(JIT)
2532     if (Options::useExceptionFuzz())
2533         printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
2534     bool fireAtEnabled =
2535     Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
2536     if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
2537         printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
2538     if (Options::useOSRExitFuzz()) {
2539         printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks());
2540         printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks());
2541     }
2542
2543     auto compileTimeStats = JIT::compileTimeStats();
2544     Vector<CString> compileTimeKeys;
2545     for (auto& entry : compileTimeStats)
2546         compileTimeKeys.append(entry.key);
2547     std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
2548     for (CString key : compileTimeKeys)
2549         printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
2550 #endif
2551
2552     return result;
2553 }
2554
2555 int jscmain(int argc, char** argv)
2556 {
2557     // Note that the options parsing can affect VM creation, and thus
2558     // comes first.
2559     CommandLine options(argc, argv);
2560
2561     // Initialize JSC before getting VM.
2562 #if ENABLE(SAMPLING_REGIONS)
2563     WTF::initializeMainThread();
2564 #endif
2565     JSC::initializeThreading();
2566
2567     VM* vm = &VM::create(LargeHeap).leakRef();
2568     int result;
2569     result = runJSC(vm, options);
2570
2571     if (Options::gcAtEnd()) {
2572         // We need to hold the API lock to do a GC.
2573         JSLockHolder locker(vm);
2574         vm->heap.collectAllGarbage();
2575     }
2576
2577     if (options.m_dumpSamplingProfilerData) {
2578 #if ENABLE(SAMPLING_PROFILER)
2579         JSLockHolder locker(vm);
2580         vm->samplingProfiler()->reportTopFunctions();
2581         vm->samplingProfiler()->reportTopBytecodes();
2582 #else
2583         dataLog("Sampling profiler is not enabled on this platform\n");
2584 #endif
2585     }
2586
2587     printSuperSamplerState();
2588
2589     return result;
2590 }
2591
2592 #if OS(WINDOWS)
2593 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
2594 {
2595     return main(argc, const_cast<char**>(argv));
2596 }
2597 #endif