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