put_by_val_direct need to check the property is index or not for using putDirect...
[WebKit-https.git] / Source / JavaScriptCore / jsc.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 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 "ButterflyInlines.h"
27 #include "BytecodeGenerator.h"
28 #include "CodeBlock.h"
29 #include "Completion.h"
30 #include "CopiedSpaceInlines.h"
31 #include "ExceptionHelpers.h"
32 #include "HeapStatistics.h"
33 #include "InitializeThreading.h"
34 #include "Interpreter.h"
35 #include "JSArray.h"
36 #include "JSArrayBuffer.h"
37 #include "JSCInlines.h"
38 #include "JSFunction.h"
39 #include "JSLock.h"
40 #include "JSONObject.h"
41 #include "JSProxy.h"
42 #include "JSString.h"
43 #include "ProfilerDatabase.h"
44 #include "SamplingTool.h"
45 #include "StackVisitor.h"
46 #include "StructureInlines.h"
47 #include "StructureRareDataInlines.h"
48 #include "TestRunnerUtils.h"
49 #include "TypeProfilerLog.h"
50 #include <math.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <thread>
55 #include <wtf/CurrentTime.h>
56 #include <wtf/MainThread.h>
57 #include <wtf/StringPrintStream.h>
58 #include <wtf/text/StringBuilder.h>
59
60 #if !OS(WINDOWS)
61 #include <unistd.h>
62 #endif
63
64 #if HAVE(READLINE)
65 // readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
66 // We #define it to something else to avoid this conflict.
67 #define Function ReadlineFunction
68 #include <readline/history.h>
69 #include <readline/readline.h>
70 #undef Function
71 #endif
72
73 #if HAVE(SYS_TIME_H)
74 #include <sys/time.h>
75 #endif
76
77 #if HAVE(SIGNAL_H)
78 #include <signal.h>
79 #endif
80
81 #if COMPILER(MSVC)
82 #include <crtdbg.h>
83 #include <mmsystem.h>
84 #include <windows.h>
85 #endif
86
87 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
88 #include <fenv.h>
89 #include <arm/arch.h>
90 #endif
91
92 #if PLATFORM(EFL)
93 #include <Ecore.h>
94 #endif
95
96 using namespace JSC;
97 using namespace WTF;
98
99 namespace JSC {
100 WTF_IMPORT extern const struct HashTable globalObjectTable;
101 }
102
103 namespace {
104
105 NO_RETURN_WITH_VALUE static void jscExit(int status)
106 {
107 #if ENABLE(DFG_JIT)
108     if (DFG::isCrashing()) {
109         for (;;) {
110 #if OS(WINDOWS)
111             Sleep(1000);
112 #else
113             pause();
114 #endif
115         }
116     }
117 #endif // ENABLE(DFG_JIT)
118     exit(status);
119 }
120
121 class Element;
122 class ElementHandleOwner;
123 class Masuqerader;
124 class Root;
125 class RuntimeArray;
126
127 class Element : public JSNonFinalObject {
128 public:
129     Element(VM& vm, Structure* structure, Root* root)
130         : Base(vm, structure)
131         , m_root(root)
132     {
133     }
134
135     typedef JSNonFinalObject Base;
136     static const bool needsDestruction = false;
137
138     Root* root() const { return m_root; }
139     void setRoot(Root* root) { m_root = root; }
140
141     static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
142     {
143         Structure* structure = createStructure(vm, globalObject, jsNull());
144         Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure, root);
145         element->finishCreation(vm);
146         return element;
147     }
148
149     void finishCreation(VM&);
150
151     static ElementHandleOwner* handleOwner();
152
153     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
154     {
155         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
156     }
157
158     DECLARE_INFO;
159
160 private:
161     Root* m_root;
162 };
163
164 class ElementHandleOwner : public WeakHandleOwner {
165 public:
166     virtual bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
167     {
168         Element* element = jsCast<Element*>(handle.slot()->asCell());
169         return visitor.containsOpaqueRoot(element->root());
170     }
171 };
172
173 class Masquerader : public JSNonFinalObject {
174 public:
175     Masquerader(VM& vm, Structure* structure)
176         : Base(vm, structure)
177     {
178     }
179
180     typedef JSNonFinalObject Base;
181
182     static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
183     {
184         globalObject->masqueradesAsUndefinedWatchpoint()->fireAll("Masquerading object allocated");
185         Structure* structure = createStructure(vm, globalObject, jsNull());
186         Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
187         result->finishCreation(vm);
188         return result;
189     }
190
191     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
192     {
193         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
194     }
195
196     DECLARE_INFO;
197
198 protected:
199     static const unsigned StructureFlags = JSC::MasqueradesAsUndefined | Base::StructureFlags;
200 };
201
202 class Root : public JSDestructibleObject {
203 public:
204     Root(VM& vm, Structure* structure)
205         : Base(vm, structure)
206     {
207     }
208
209     Element* element()
210     {
211         return m_element.get();
212     }
213
214     void setElement(Element* element)
215     {
216         Weak<Element> newElement(element, Element::handleOwner());
217         m_element.swap(newElement);
218     }
219
220     static Root* create(VM& vm, JSGlobalObject* globalObject)
221     {
222         Structure* structure = createStructure(vm, globalObject, jsNull());
223         Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
224         root->finishCreation(vm);
225         return root;
226     }
227
228     typedef JSDestructibleObject Base;
229
230     DECLARE_INFO;
231     static const bool needsDestruction = true;
232
233     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
234     {
235         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
236     }
237
238     static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
239     {
240         Base::visitChildren(thisObject, visitor);
241         visitor.addOpaqueRoot(thisObject);
242     }
243
244 private:
245     Weak<Element> m_element;
246 };
247
248 class ImpureGetter : public JSNonFinalObject {
249 public:
250     ImpureGetter(VM& vm, Structure* structure)
251         : Base(vm, structure)
252     {
253     }
254
255     DECLARE_INFO;
256     typedef JSNonFinalObject Base;
257
258     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
259     {
260         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
261     }
262
263     static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
264     {
265         ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
266         getter->finishCreation(vm, delegate);
267         return getter;
268     }
269
270     void finishCreation(VM& vm, JSObject* delegate)
271     {
272         Base::finishCreation(vm);
273         if (delegate)
274             m_delegate.set(vm, this, delegate);
275     }
276
277     static const unsigned StructureFlags = JSC::HasImpureGetOwnPropertySlot | JSC::OverridesGetOwnPropertySlot | Base::StructureFlags;
278
279     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
280     {
281         ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
282         
283         if (thisObject->m_delegate && thisObject->m_delegate->getPropertySlot(exec, name, slot))
284             return true;
285
286         return Base::getOwnPropertySlot(object, exec, name, slot);
287     }
288
289     static void visitChildren(JSCell* cell, SlotVisitor& visitor)
290     {
291         Base::visitChildren(cell, visitor);
292         ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell);
293         visitor.append(&thisObject->m_delegate);
294     }
295
296     void setDelegate(VM& vm, JSObject* delegate)
297     {
298         m_delegate.set(vm, this, delegate);
299     }
300
301 private:
302     WriteBarrier<JSObject> m_delegate;
303 };
304
305 class RuntimeArray : public JSArray {
306 public:
307     typedef JSArray Base;
308
309     static RuntimeArray* create(ExecState* exec)
310     {
311         VM& vm = exec->vm();
312         JSGlobalObject* globalObject = exec->lexicalGlobalObject();
313         Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
314         RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
315         runtimeArray->finishCreation(exec);
316         vm.heap.addFinalizer(runtimeArray, destroy);
317         return runtimeArray;
318     }
319
320     ~RuntimeArray() { }
321
322     static void destroy(JSCell* cell)
323     {
324         static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
325     }
326
327     static const bool needsDestruction = false;
328
329     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
330     {
331         RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
332         if (propertyName == exec->propertyNames().length) {
333             slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
334             return true;
335         }
336
337         Optional<uint32_t> index = propertyName.asIndex();
338         if (index && index.value() < thisObject->getLength()) {
339             slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
340             return true;
341         }
342
343         return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
344     }
345
346     static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
347     {
348         RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
349         if (index < thisObject->getLength()) {
350             slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
351             return true;
352         }
353
354         return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
355     }
356
357     static NO_RETURN_DUE_TO_CRASH void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
358     {
359         RELEASE_ASSERT_NOT_REACHED();
360     }
361
362     static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
363     {
364         RELEASE_ASSERT_NOT_REACHED();
365 #if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
366         return true;
367 #endif
368     }
369
370     unsigned getLength() const { return m_vector.size(); }
371
372     DECLARE_INFO;
373
374     static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
375     {
376         return globalObject->arrayPrototype();
377     }
378
379     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
380     {
381         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
382     }
383
384 protected:
385     void finishCreation(ExecState* exec)
386     {
387         Base::finishCreation(exec->vm());
388         ASSERT(inherits(info()));
389
390         for (size_t i = 0; i < exec->argumentCount(); i++)
391             m_vector.append(exec->argument(i).toInt32(exec));
392     }
393
394     static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSArray::StructureFlags;
395
396 private:
397     RuntimeArray(ExecState* exec, Structure* structure)
398         : JSArray(exec->vm(), structure, 0)
399     {
400     }
401
402     static EncodedJSValue lengthGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
403     {
404         RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
405         if (!thisObject)
406             return throwVMTypeError(exec);
407         return JSValue::encode(jsNumber(thisObject->getLength()));
408     }
409
410     Vector<int> m_vector;
411 };
412
413 const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
414 const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
415 const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
416 const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
417 const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
418
419 ElementHandleOwner* Element::handleOwner()
420 {
421     static ElementHandleOwner* owner = 0;
422     if (!owner)
423         owner = new ElementHandleOwner();
424     return owner;
425 }
426
427 void Element::finishCreation(VM& vm)
428 {
429     Base::finishCreation(vm);
430     m_root->setElement(this);
431 }
432
433 }
434
435 static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
436
437 static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
438 static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
439 static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
440 static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
441
442 static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
443 static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
444 static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
445 static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
446 static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
447 static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
448 static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
449 static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
450 static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
451 static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
452 static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
453 static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
454 static EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState*);
455 #ifndef NDEBUG
456 static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
457 static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
458 #endif
459 static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
460 static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
461 static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
462 static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
463 static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
464 static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
465 static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
466 static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
467 static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
468 static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
469 static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
470 static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
471 static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
472 static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
473 static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
474 static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
475 static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
476 static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
477 static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
478 static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
479 static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
480 static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
481 static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
482 static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
483 static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
484
485 #if ENABLE(SAMPLING_FLAGS)
486 static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
487 static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
488 #endif
489
490 struct Script {
491     bool isFile;
492     char* argument;
493
494     Script(bool isFile, char *argument)
495         : isFile(isFile)
496         , argument(argument)
497     {
498     }
499 };
500
501 class CommandLine {
502 public:
503     CommandLine(int argc, char** argv)
504         : m_interactive(false)
505         , m_dump(false)
506         , m_exitCode(false)
507         , m_profile(false)
508     {
509         parseArguments(argc, argv);
510     }
511
512     bool m_interactive;
513     bool m_dump;
514     bool m_exitCode;
515     Vector<Script> m_scripts;
516     Vector<String> m_arguments;
517     bool m_profile;
518     String m_profilerOutput;
519
520     void parseArguments(int, char**);
521 };
522
523 static const char interactivePrompt[] = ">>> ";
524
525 class StopWatch {
526 public:
527     void start();
528     void stop();
529     long getElapsedMS(); // call stop() first
530
531 private:
532     double m_startTime;
533     double m_stopTime;
534 };
535
536 void StopWatch::start()
537 {
538     m_startTime = monotonicallyIncreasingTime();
539 }
540
541 void StopWatch::stop()
542 {
543     m_stopTime = monotonicallyIncreasingTime();
544 }
545
546 long StopWatch::getElapsedMS()
547 {
548     return static_cast<long>((m_stopTime - m_startTime) * 1000);
549 }
550
551 class GlobalObject : public JSGlobalObject {
552 private:
553     GlobalObject(VM&, Structure*);
554
555 public:
556     typedef JSGlobalObject Base;
557
558     static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
559     {
560         GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
561         object->finishCreation(vm, arguments);
562         vm.heap.addFinalizer(object, destroy);
563         return object;
564     }
565
566     static const bool needsDestruction = false;
567
568     DECLARE_INFO;
569     static const GlobalObjectMethodTable s_globalObjectMethodTable;
570
571     static Structure* createStructure(VM& vm, JSValue prototype)
572     {
573         return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
574     }
575
576     static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
577
578 protected:
579     void finishCreation(VM& vm, const Vector<String>& arguments)
580     {
581         Base::finishCreation(vm);
582         
583         addFunction(vm, "debug", functionDebug, 1);
584         addFunction(vm, "describe", functionDescribe, 1);
585         addFunction(vm, "describeArray", functionDescribeArray, 1);
586         addFunction(vm, "print", functionPrint, 1);
587         addFunction(vm, "quit", functionQuit, 0);
588         addFunction(vm, "gc", functionGCAndSweep, 0);
589         addFunction(vm, "fullGC", functionFullGC, 0);
590         addFunction(vm, "edenGC", functionEdenGC, 0);
591         addFunction(vm, "deleteAllCompiledCode", functionDeleteAllCompiledCode, 0);
592 #ifndef NDEBUG
593         addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
594         addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
595 #endif
596         addFunction(vm, "version", functionVersion, 1);
597         addFunction(vm, "run", functionRun, 1);
598         addFunction(vm, "load", functionLoad, 1);
599         addFunction(vm, "readFile", functionReadFile, 1);
600         addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
601         addFunction(vm, "jscStack", functionJSCStack, 1);
602         addFunction(vm, "readline", functionReadline, 0);
603         addFunction(vm, "preciseTime", functionPreciseTime, 0);
604         addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
605         addFunction(vm, "noInline", functionNeverInlineFunction, 1);
606         addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
607         addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
608         addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
609         addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
610 #if ENABLE(SAMPLING_FLAGS)
611         addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
612         addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
613 #endif
614         addConstructableFunction(vm, "Root", functionCreateRoot, 0);
615         addConstructableFunction(vm, "Element", functionCreateElement, 1);
616         addFunction(vm, "getElement", functionGetElement, 1);
617         addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
618         
619         putDirectNativeFunction(vm, this, Identifier(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum | JSC::Function);
620         putDirectNativeFunction(vm, this, Identifier(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum | JSC::Function);
621         putDirectNativeFunction(vm, this, Identifier(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum | JSC::Function);
622         putDirectNativeFunction(vm, this, Identifier(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum | JSC::Function);
623         putDirectNativeFunction(vm, this, Identifier(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum | JSC::Function);
624         
625         addFunction(vm, "effectful42", functionEffectful42, 0);
626         addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
627         addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
628
629         addFunction(vm, "createProxy", functionCreateProxy, 1);
630         addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
631
632         addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
633         addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
634
635         addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
636         addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
637         addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
638
639         addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
640         
641         JSArray* array = constructEmptyArray(globalExec(), 0);
642         for (size_t i = 0; i < arguments.size(); ++i)
643             array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
644         putDirect(vm, Identifier(globalExec(), "arguments"), array);
645         
646         putDirect(vm, Identifier(globalExec(), "console"), jsUndefined());
647     }
648
649     void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
650     {
651         Identifier identifier(&vm, name);
652         putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
653     }
654     
655     void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
656     {
657         Identifier identifier(&vm, name);
658         putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
659     }
660 };
661
662 const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, &globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
663 const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0, &shouldInterruptScriptBeforeTimeout };
664
665
666 GlobalObject::GlobalObject(VM& vm, Structure* structure)
667     : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
668 {
669 }
670
671 static inline String stringFromUTF(const char* utf8)
672 {
673     return String::fromUTF8WithLatin1Fallback(utf8, strlen(utf8));
674 }
675
676 static inline SourceCode jscSource(const char* utf8, const String& filename)
677 {
678     String str = stringFromUTF(utf8);
679     return makeSource(str, filename);
680 }
681
682 EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
683 {
684     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
685         if (i)
686             putchar(' ');
687
688         printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data());
689     }
690
691     putchar('\n');
692     fflush(stdout);
693     return JSValue::encode(jsUndefined());
694 }
695
696 #ifndef NDEBUG
697 EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
698 {
699     VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
700     ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
701     if (callerFrame)
702         exec->vm().interpreter->dumpCallFrame(callerFrame);
703     return JSValue::encode(jsUndefined());
704 }
705 #endif
706
707 EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
708 {
709     fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
710     return JSValue::encode(jsUndefined());
711 }
712
713 EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
714 {
715     if (exec->argumentCount() < 1)
716         return JSValue::encode(jsUndefined());
717     return JSValue::encode(jsString(exec, toString(exec->argument(0))));
718 }
719
720 EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
721 {
722     if (exec->argumentCount() < 1)
723         return JSValue::encode(jsUndefined());
724     JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
725     if (!object)
726         return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
727     return JSValue::encode(jsNontrivialString(exec, toString("<Public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
728 }
729
730 class FunctionJSCStackFunctor {
731 public:
732     FunctionJSCStackFunctor(StringBuilder& trace)
733         : m_trace(trace)
734     {
735     }
736
737     StackVisitor::Status operator()(StackVisitor& visitor)
738     {
739         m_trace.append(String::format("    %zu   %s\n", visitor->index(), visitor->toString().utf8().data()));
740         return StackVisitor::Continue;
741     }
742
743 private:
744     StringBuilder& m_trace;
745 };
746
747 EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
748 {
749     StringBuilder trace;
750     trace.appendLiteral("--> Stack trace:\n");
751
752     FunctionJSCStackFunctor functor(trace);
753     exec->iterate(functor);
754     fprintf(stderr, "%s", trace.toString().utf8().data());
755     return JSValue::encode(jsUndefined());
756 }
757
758 EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
759 {
760     JSLockHolder lock(exec);
761     return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
762 }
763
764 EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
765 {
766     JSLockHolder lock(exec);
767     JSValue arg = exec->argument(0);
768     return JSValue::encode(Element::create(exec->vm(), exec->lexicalGlobalObject(), arg.isNull() ? nullptr : jsCast<Root*>(exec->argument(0))));
769 }
770
771 EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
772 {
773     JSLockHolder lock(exec);
774     Element* result = jsCast<Root*>(exec->argument(0).asCell())->element();
775     return JSValue::encode(result ? result : jsUndefined());
776 }
777
778 EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
779 {
780     JSLockHolder lock(exec);
781     Element* element = jsCast<Element*>(exec->argument(0));
782     Root* root = jsCast<Root*>(exec->argument(1));
783     element->setRoot(root);
784     return JSValue::encode(jsUndefined());
785 }
786
787 EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
788 {
789     JSLockHolder lock(exec);
790     JSValue target = exec->argument(0);
791     if (!target.isObject())
792         return JSValue::encode(jsUndefined());
793     JSObject* jsTarget = asObject(target.asCell());
794     Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->prototype());
795     JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
796     return JSValue::encode(proxy);
797 }
798
799 EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
800 {
801     JSLockHolder lock(exec);
802     RuntimeArray* array = RuntimeArray::create(exec);
803     return JSValue::encode(array);
804 }
805
806 EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
807 {
808     JSLockHolder lock(exec);
809     JSValue target = exec->argument(0);
810     JSObject* delegate = nullptr;
811     if (target.isObject())
812         delegate = asObject(target.asCell());
813     Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
814     ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
815     return JSValue::encode(result);
816 }
817
818 EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
819 {
820     JSLockHolder lock(exec);
821     JSValue base = exec->argument(0);
822     if (!base.isObject())
823         return JSValue::encode(jsUndefined());
824     JSValue delegate = exec->argument(1);
825     if (!delegate.isObject())
826         return JSValue::encode(jsUndefined());
827     ImpureGetter* impureGetter = jsCast<ImpureGetter*>(asObject(base.asCell()));
828     impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));
829     return JSValue::encode(jsUndefined());
830 }
831
832 EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
833 {
834     JSLockHolder lock(exec);
835     exec->heap()->collectAllGarbage();
836     return JSValue::encode(jsUndefined());
837 }
838
839 EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
840 {
841     JSLockHolder lock(exec);
842     exec->heap()->collect(FullCollection);
843     return JSValue::encode(jsUndefined());
844 }
845
846 EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
847 {
848     JSLockHolder lock(exec);
849     exec->heap()->collect(EdenCollection);
850     return JSValue::encode(jsUndefined());
851 }
852
853 EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState* exec)
854 {
855     JSLockHolder lock(exec);
856     exec->heap()->deleteAllCompiledCode();
857     return JSValue::encode(jsUndefined());
858 }
859
860 #ifndef NDEBUG
861 EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
862 {
863     JSLockHolder lock(exec);
864     exec->vm().releaseExecutableMemory();
865     return JSValue::encode(jsUndefined());
866 }
867 #endif
868
869 EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
870 {
871     // We need this function for compatibility with the Mozilla JS tests but for now
872     // we don't actually do any version-specific handling
873     return JSValue::encode(jsUndefined());
874 }
875
876 EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
877 {
878     String fileName = exec->argument(0).toString(exec)->value(exec);
879     Vector<char> script;
880     if (!fillBufferWithContentsOfFile(fileName, script))
881         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
882
883     GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
884
885     JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
886     for (unsigned i = 1; i < exec->argumentCount(); ++i)
887         array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
888     globalObject->putDirect(
889         exec->vm(), Identifier(globalObject->globalExec(), "arguments"), array);
890
891     JSValue exception;
892     StopWatch stopWatch;
893     stopWatch.start();
894     evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
895     stopWatch.stop();
896
897     if (!!exception) {
898         exec->vm().throwException(globalObject->globalExec(), exception);
899         return JSValue::encode(jsUndefined());
900     }
901     
902     return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
903 }
904
905 EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
906 {
907     String fileName = exec->argument(0).toString(exec)->value(exec);
908     Vector<char> script;
909     if (!fillBufferWithContentsOfFile(fileName, script))
910         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
911
912     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
913     
914     JSValue evaluationException;
915     JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
916     if (evaluationException)
917         exec->vm().throwException(exec, evaluationException);
918     return JSValue::encode(result);
919 }
920
921 EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
922 {
923     String fileName = exec->argument(0).toString(exec)->value(exec);
924     Vector<char> script;
925     if (!fillBufferWithContentsOfFile(fileName, script))
926         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
927
928     return JSValue::encode(jsString(exec, stringFromUTF(script.data())));
929 }
930
931 EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
932 {
933     String fileName = exec->argument(0).toString(exec)->value(exec);
934     Vector<char> script;
935     if (!fillBufferWithContentsOfFile(fileName, script))
936         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
937
938     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
939
940     StopWatch stopWatch;
941     stopWatch.start();
942
943     JSValue syntaxException;
944     bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
945     stopWatch.stop();
946
947     if (!validSyntax)
948         exec->vm().throwException(exec, syntaxException);
949     return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
950 }
951
952 #if ENABLE(SAMPLING_FLAGS)
953 EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
954 {
955     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
956         unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
957         if ((flag >= 1) && (flag <= 32))
958             SamplingFlags::setFlag(flag);
959     }
960     return JSValue::encode(jsNull());
961 }
962
963 EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
964 {
965     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
966         unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
967         if ((flag >= 1) && (flag <= 32))
968             SamplingFlags::clearFlag(flag);
969     }
970     return JSValue::encode(jsNull());
971 }
972 #endif
973
974 EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
975 {
976     Vector<char, 256> line;
977     int c;
978     while ((c = getchar()) != EOF) {
979         // FIXME: Should we also break on \r? 
980         if (c == '\n')
981             break;
982         line.append(c);
983     }
984     line.append('\0');
985     return JSValue::encode(jsString(exec, line.data()));
986 }
987
988 EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
989 {
990     return JSValue::encode(jsNumber(currentTime()));
991 }
992
993 EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
994 {
995     return JSValue::encode(setNeverInline(exec));
996 }
997
998 EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
999 {
1000     return JSValue::encode(optimizeNextInvocation(exec));
1001 }
1002
1003 EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
1004 {
1005     return JSValue::encode(numberOfDFGCompiles(exec));
1006 }
1007
1008 EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1009 {
1010     if (exec->argumentCount() < 1)
1011         return JSValue::encode(jsUndefined());
1012     
1013     CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1014     if (!block)
1015         return JSValue::encode(jsNumber(0));
1016     
1017     return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1018 }
1019
1020 EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1021 {
1022     if (exec->argumentCount() < 1)
1023         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Not enough arguments"))));
1024     
1025     JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1026     if (!buffer)
1027         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Expected an array buffer"))));
1028     
1029     ArrayBufferContents dummyContents;
1030     buffer->impl()->transfer(dummyContents);
1031     
1032     return JSValue::encode(jsUndefined());
1033 }
1034
1035 EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1036 {
1037     jscExit(EXIT_SUCCESS);
1038
1039 #if COMPILER(MSVC)
1040     // Without this, Visual Studio will complain that this method does not return a value.
1041     return JSValue::encode(jsUndefined());
1042 #endif
1043 }
1044
1045 EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1046 EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1047
1048 EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1049 EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1050
1051 EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1052
1053 EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1054 {
1055     return JSValue::encode(jsNumber(42));
1056 }
1057
1058 EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1059 {
1060     return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1061 }
1062
1063 EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1064 {
1065     JSValue value = exec->argument(0);
1066     if (value.isObject())
1067         return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1068     return JSValue::encode(jsBoolean(false));
1069 }
1070
1071 EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1072 {
1073     exec->vm().dumpTypeProfilerData();
1074     return JSValue::encode(jsUndefined());
1075 }
1076
1077 EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
1078 {
1079     RELEASE_ASSERT(exec->vm().typeProfiler());
1080     exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
1081
1082     JSValue functionValue = exec->argument(0);
1083     RELEASE_ASSERT(functionValue.isFunction());
1084     FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1085
1086     RELEASE_ASSERT(exec->argument(1).isString());
1087     String substring = exec->argument(1).getString(exec);
1088     String sourceCodeText = executable->source().toString();
1089     unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
1090     
1091     String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
1092     return JSValue::encode(JSONParse(exec, jsonString));
1093 }
1094
1095 EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
1096 {
1097     RELEASE_ASSERT(exec->vm().typeProfiler());
1098     exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
1099
1100     JSValue functionValue = exec->argument(0);
1101     RELEASE_ASSERT(functionValue.isFunction());
1102     FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1103
1104     unsigned offset = executable->source().startOffset();
1105     String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
1106     return JSValue::encode(JSONParse(exec, jsonString));
1107 }
1108
1109 EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
1110 {
1111     RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1112     exec->vm().controlFlowProfiler()->dumpData();
1113     return JSValue::encode(jsUndefined());
1114 }
1115
1116 // Use SEH for Release builds only to get rid of the crash report dialog
1117 // (luckily the same tests fail in Release and Debug builds so far). Need to
1118 // be in a separate main function because the jscmain function requires object
1119 // unwinding.
1120
1121 #if COMPILER(MSVC) && !defined(_DEBUG)
1122 #define TRY       __try {
1123 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
1124 #else
1125 #define TRY
1126 #define EXCEPT(x)
1127 #endif
1128
1129 int jscmain(int argc, char** argv);
1130
1131 static double s_desiredTimeout;
1132
1133 static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
1134 {
1135     auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
1136     std::this_thread::sleep_for(timeout);
1137     
1138     dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
1139     CRASH();
1140 }
1141
1142 int main(int argc, char** argv)
1143 {
1144 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
1145     // Enabled IEEE754 denormal support.
1146     fenv_t env;
1147     fegetenv( &env );
1148     env.__fpscr &= ~0x01000000u;
1149     fesetenv( &env );
1150 #endif
1151
1152 #if OS(WINDOWS)
1153     // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1154     // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1155     // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1156     ::SetErrorMode(0);
1157
1158 #if defined(_DEBUG)
1159     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1160     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1161     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1162     _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1163     _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1164     _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1165 #endif
1166
1167     timeBeginPeriod(1);
1168 #endif
1169
1170 #if PLATFORM(EFL)
1171     ecore_init();
1172 #endif
1173
1174     // Initialize JSC before getting VM.
1175 #if ENABLE(SAMPLING_REGIONS)
1176     WTF::initializeMainThread();
1177 #endif
1178     JSC::initializeThreading();
1179
1180     if (char* timeoutString = getenv("JSC_timeout")) {
1181         if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
1182             dataLog(
1183                 "WARNING: timeout string is malformed, got ", timeoutString,
1184                 " but expected a number. Not using a timeout.\n");
1185         } else
1186             createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
1187     }
1188
1189 #if PLATFORM(IOS)
1190     Options::crashIfCantAllocateJITMemory() = true;
1191 #endif
1192
1193     // We can't use destructors in the following code because it uses Windows
1194     // Structured Exception Handling
1195     int res = 0;
1196     TRY
1197         res = jscmain(argc, argv);
1198     EXCEPT(res = 3)
1199     if (Options::logHeapStatisticsAtExit())
1200         HeapStatistics::reportSuccess();
1201
1202 #if PLATFORM(EFL)
1203     ecore_shutdown();
1204 #endif
1205
1206     jscExit(res);
1207 }
1208
1209 static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
1210 {
1211     const char* script;
1212     String fileName;
1213     Vector<char> scriptBuffer;
1214
1215     if (dump)
1216         JSC::Options::dumpGeneratedBytecodes() = true;
1217
1218     VM& vm = globalObject->vm();
1219
1220 #if ENABLE(SAMPLING_FLAGS)
1221     SamplingFlags::start();
1222 #endif
1223
1224     bool success = true;
1225     for (size_t i = 0; i < scripts.size(); i++) {
1226         if (scripts[i].isFile) {
1227             fileName = scripts[i].argument;
1228             if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
1229                 return false; // fail early so we can catch missing files
1230             script = scriptBuffer.data();
1231         } else {
1232             script = scripts[i].argument;
1233             fileName = ASCIILiteral("[Command Line]");
1234         }
1235
1236         vm.startSampling();
1237
1238         JSValue evaluationException;
1239         JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
1240         success = success && !evaluationException;
1241         if (dump && !evaluationException)
1242             printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1243         if (evaluationException) {
1244             printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1245             Identifier stackID(globalObject->globalExec(), "stack");
1246             JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
1247             if (!stackValue.isUndefinedOrNull())
1248                 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1249         }
1250
1251         vm.stopSampling();
1252         globalObject->globalExec()->clearException();
1253     }
1254
1255 #if ENABLE(SAMPLING_FLAGS)
1256     SamplingFlags::stop();
1257 #endif
1258 #if ENABLE(SAMPLING_REGIONS)
1259     SamplingRegion::dump();
1260 #endif
1261     vm.dumpSampleData(globalObject->globalExec());
1262 #if ENABLE(SAMPLING_COUNTERS)
1263     AbstractSamplingCounter::dump();
1264 #endif
1265 #if ENABLE(REGEXP_TRACING)
1266     vm.dumpRegExpTrace();
1267 #endif
1268     return success;
1269 }
1270
1271 #define RUNNING_FROM_XCODE 0
1272
1273 static void runInteractive(GlobalObject* globalObject)
1274 {
1275     String interpreterName(ASCIILiteral("Interpreter"));
1276     
1277     bool shouldQuit = false;
1278     while (!shouldQuit) {
1279 #if HAVE(READLINE) && !RUNNING_FROM_XCODE
1280         ParserError error;
1281         String source;
1282         do {
1283             error = ParserError();
1284             char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
1285             shouldQuit = !line;
1286             if (!line)
1287                 break;
1288             source = source + line;
1289             source = source + '\n';
1290             checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
1291             if (!line[0])
1292                 break;
1293             add_history(line);
1294         } while (error.m_syntaxErrorType == ParserError::SyntaxErrorRecoverable);
1295         
1296         if (error.m_type != ParserError::ErrorNone) {
1297             printf("%s:%d\n", error.m_message.utf8().data(), error.m_line);
1298             continue;
1299         }
1300         
1301         
1302         JSValue evaluationException;
1303         JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
1304 #else
1305         printf("%s", interactivePrompt);
1306         Vector<char, 256> line;
1307         int c;
1308         while ((c = getchar()) != EOF) {
1309             // FIXME: Should we also break on \r? 
1310             if (c == '\n')
1311                 break;
1312             line.append(c);
1313         }
1314         if (line.isEmpty())
1315             break;
1316         line.append('\0');
1317
1318         JSValue evaluationException;
1319         JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
1320 #endif
1321         if (evaluationException)
1322             printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1323         else
1324             printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1325
1326         globalObject->globalExec()->clearException();
1327     }
1328     printf("\n");
1329 }
1330
1331 static NO_RETURN void printUsageStatement(bool help = false)
1332 {
1333     fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1334     fprintf(stderr, "  -d         Dumps bytecode (debug builds only)\n");
1335     fprintf(stderr, "  -e         Evaluate argument as script code\n");
1336     fprintf(stderr, "  -f         Specifies a source file (deprecated)\n");
1337     fprintf(stderr, "  -h|--help  Prints this help message\n");
1338     fprintf(stderr, "  -i         Enables interactive mode (default if no files are specified)\n");
1339 #if HAVE(SIGNAL_H)
1340     fprintf(stderr, "  -s         Installs signal handlers that exit on a crash (Unix platforms only)\n");
1341 #endif
1342     fprintf(stderr, "  -p <file>  Outputs profiling data to a file\n");
1343     fprintf(stderr, "  -x         Output exit code before terminating\n");
1344     fprintf(stderr, "\n");
1345     fprintf(stderr, "  --options                  Dumps all JSC VM options and exits\n");
1346     fprintf(stderr, "  --dumpOptions              Dumps all JSC VM options before continuing\n");
1347     fprintf(stderr, "  --<jsc VM option>=<value>  Sets the specified JSC VM option\n");
1348     fprintf(stderr, "\n");
1349
1350     jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1351 }
1352
1353 void CommandLine::parseArguments(int argc, char** argv)
1354 {
1355     int i = 1;
1356     bool needToDumpOptions = false;
1357     bool needToExit = false;
1358
1359     for (; i < argc; ++i) {
1360         const char* arg = argv[i];
1361         if (!strcmp(arg, "-f")) {
1362             if (++i == argc)
1363                 printUsageStatement();
1364             m_scripts.append(Script(true, argv[i]));
1365             continue;
1366         }
1367         if (!strcmp(arg, "-e")) {
1368             if (++i == argc)
1369                 printUsageStatement();
1370             m_scripts.append(Script(false, argv[i]));
1371             continue;
1372         }
1373         if (!strcmp(arg, "-i")) {
1374             m_interactive = true;
1375             continue;
1376         }
1377         if (!strcmp(arg, "-d")) {
1378             m_dump = true;
1379             continue;
1380         }
1381         if (!strcmp(arg, "-p")) {
1382             if (++i == argc)
1383                 printUsageStatement();
1384             m_profile = true;
1385             m_profilerOutput = argv[i];
1386             continue;
1387         }
1388         if (!strcmp(arg, "-s")) {
1389 #if HAVE(SIGNAL_H)
1390             signal(SIGILL, _exit);
1391             signal(SIGFPE, _exit);
1392             signal(SIGBUS, _exit);
1393             signal(SIGSEGV, _exit);
1394 #endif
1395             continue;
1396         }
1397         if (!strcmp(arg, "-x")) {
1398             m_exitCode = true;
1399             continue;
1400         }
1401         if (!strcmp(arg, "--")) {
1402             ++i;
1403             break;
1404         }
1405         if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1406             printUsageStatement(true);
1407
1408         if (!strcmp(arg, "--options")) {
1409             needToDumpOptions = true;
1410             needToExit = true;
1411             continue;
1412         }
1413         if (!strcmp(arg, "--dumpOptions")) {
1414             needToDumpOptions = true;
1415             continue;
1416         }
1417
1418         // See if the -- option is a JSC VM option.
1419         // NOTE: At this point, we know that the arg starts with "--". Skip it.
1420         if (JSC::Options::setOption(&arg[2])) {
1421             // The arg was recognized as a VM option and has been parsed.
1422             continue; // Just continue with the next arg. 
1423         }
1424
1425         // This arg is not recognized by the VM nor by jsc. Pass it on to the
1426         // script.
1427         m_scripts.append(Script(true, argv[i]));
1428     }
1429
1430     if (m_scripts.isEmpty())
1431         m_interactive = true;
1432
1433     for (; i < argc; ++i)
1434         m_arguments.append(argv[i]);
1435
1436     if (needToDumpOptions)
1437         JSC::Options::dumpAllOptions(stderr);
1438     if (needToExit)
1439         jscExit(EXIT_SUCCESS);
1440 }
1441
1442 int jscmain(int argc, char** argv)
1443 {
1444     // Note that the options parsing can affect VM creation, and thus
1445     // comes first.
1446     CommandLine options(argc, argv);
1447     VM* vm = VM::create(LargeHeap).leakRef();
1448     int result;
1449     {
1450         JSLockHolder locker(vm);
1451
1452         if (options.m_profile && !vm->m_perBytecodeProfiler)
1453             vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
1454     
1455         GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
1456         bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
1457         if (options.m_interactive && success)
1458             runInteractive(globalObject);
1459
1460         result = success ? 0 : 3;
1461
1462         if (options.m_exitCode)
1463             printf("jsc exiting %d\n", result);
1464     
1465         if (options.m_profile) {
1466             if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
1467                 fprintf(stderr, "could not save profiler output.\n");
1468         }
1469         
1470 #if ENABLE(JIT)
1471         if (Options::enableExceptionFuzz())
1472             printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
1473 #endif
1474     }
1475     
1476     return result;
1477 }
1478
1479 static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1480 {
1481     FILE* f = fopen(fileName.utf8().data(), "r");
1482     if (!f) {
1483         fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1484         return false;
1485     }
1486
1487     size_t bufferSize = 0;
1488     size_t bufferCapacity = 1024;
1489
1490     buffer.resize(bufferCapacity);
1491
1492     while (!feof(f) && !ferror(f)) {
1493         bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
1494         if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
1495             bufferCapacity *= 2;
1496             buffer.resize(bufferCapacity);
1497         }
1498     }
1499     fclose(f);
1500     buffer[bufferSize] = '\0';
1501
1502     if (buffer[0] == '#' && buffer[1] == '!')
1503         buffer[0] = buffer[1] = '/';
1504
1505     return true;
1506 }
1507
1508 #if OS(WINDOWS)
1509 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
1510 {
1511     return main(argc, const_cast<char**>(argv));
1512 }
1513 #endif