d0a5d386d4d094913ef54f0375cfd686d98965e6
[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 WTF_IMPORT 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("Masquerading object allocated");
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 | 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     return String::fromUTF8WithLatin1Fallback(utf8, strlen(utf8));
665 }
666
667 static inline SourceCode jscSource(const char* utf8, const String& filename)
668 {
669     String str = stringFromUTF(utf8);
670     return makeSource(str, filename);
671 }
672
673 EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
674 {
675     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
676         if (i)
677             putchar(' ');
678
679         printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data());
680     }
681
682     putchar('\n');
683     fflush(stdout);
684     return JSValue::encode(jsUndefined());
685 }
686
687 #ifndef NDEBUG
688 EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
689 {
690     VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
691     ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
692     if (callerFrame)
693         exec->vm().interpreter->dumpCallFrame(callerFrame);
694     return JSValue::encode(jsUndefined());
695 }
696 #endif
697
698 EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
699 {
700     fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
701     return JSValue::encode(jsUndefined());
702 }
703
704 EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
705 {
706     if (exec->argumentCount() < 1)
707         return JSValue::encode(jsUndefined());
708     return JSValue::encode(jsString(exec, toString(exec->argument(0))));
709 }
710
711 EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
712 {
713     if (exec->argumentCount() < 1)
714         return JSValue::encode(jsUndefined());
715     JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
716     if (!object)
717         return JSValue::encode(jsString(exec, "<not object>"));
718     return JSValue::encode(jsString(exec, toString("<Public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
719 }
720
721 class FunctionJSCStackFunctor {
722 public:
723     FunctionJSCStackFunctor(StringBuilder& trace)
724         : m_trace(trace)
725     {
726     }
727
728     StackVisitor::Status operator()(StackVisitor& visitor)
729     {
730         m_trace.append(String::format("    %zu   %s\n", visitor->index(), visitor->toString().utf8().data()));
731         return StackVisitor::Continue;
732     }
733
734 private:
735     StringBuilder& m_trace;
736 };
737
738 EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
739 {
740     StringBuilder trace;
741     trace.appendLiteral("--> Stack trace:\n");
742
743     FunctionJSCStackFunctor functor(trace);
744     exec->iterate(functor);
745     fprintf(stderr, "%s", trace.toString().utf8().data());
746     return JSValue::encode(jsUndefined());
747 }
748
749 EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
750 {
751     JSLockHolder lock(exec);
752     return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
753 }
754
755 EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
756 {
757     JSLockHolder lock(exec);
758     JSValue arg = exec->argument(0);
759     return JSValue::encode(Element::create(exec->vm(), exec->lexicalGlobalObject(), arg.isNull() ? nullptr : jsCast<Root*>(exec->argument(0))));
760 }
761
762 EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
763 {
764     JSLockHolder lock(exec);
765     Element* result = jsCast<Root*>(exec->argument(0).asCell())->element();
766     return JSValue::encode(result ? result : jsUndefined());
767 }
768
769 EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
770 {
771     JSLockHolder lock(exec);
772     Element* element = jsCast<Element*>(exec->argument(0));
773     Root* root = jsCast<Root*>(exec->argument(1));
774     element->setRoot(root);
775     return JSValue::encode(jsUndefined());
776 }
777
778 EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
779 {
780     JSLockHolder lock(exec);
781     JSValue target = exec->argument(0);
782     if (!target.isObject())
783         return JSValue::encode(jsUndefined());
784     JSObject* jsTarget = asObject(target.asCell());
785     Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->prototype());
786     JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
787     return JSValue::encode(proxy);
788 }
789
790 EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
791 {
792     JSLockHolder lock(exec);
793     RuntimeArray* array = RuntimeArray::create(exec);
794     return JSValue::encode(array);
795 }
796
797 EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
798 {
799     JSLockHolder lock(exec);
800     JSValue target = exec->argument(0);
801     JSObject* delegate = nullptr;
802     if (target.isObject())
803         delegate = asObject(target.asCell());
804     Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
805     ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
806     return JSValue::encode(result);
807 }
808
809 EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
810 {
811     JSLockHolder lock(exec);
812     JSValue base = exec->argument(0);
813     if (!base.isObject())
814         return JSValue::encode(jsUndefined());
815     JSValue delegate = exec->argument(1);
816     if (!delegate.isObject())
817         return JSValue::encode(jsUndefined());
818     ImpureGetter* impureGetter = jsCast<ImpureGetter*>(asObject(base.asCell()));
819     impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));
820     return JSValue::encode(jsUndefined());
821 }
822
823 EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
824 {
825     JSLockHolder lock(exec);
826     exec->heap()->collectAllGarbage();
827     return JSValue::encode(jsUndefined());
828 }
829
830 EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
831 {
832     JSLockHolder lock(exec);
833     exec->heap()->collect(FullCollection);
834     return JSValue::encode(jsUndefined());
835 }
836
837 EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
838 {
839     JSLockHolder lock(exec);
840     exec->heap()->collect(EdenCollection);
841     return JSValue::encode(jsUndefined());
842 }
843
844 EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState* exec)
845 {
846     JSLockHolder lock(exec);
847     exec->heap()->deleteAllCompiledCode();
848     return JSValue::encode(jsUndefined());
849 }
850
851 #ifndef NDEBUG
852 EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
853 {
854     JSLockHolder lock(exec);
855     exec->vm().releaseExecutableMemory();
856     return JSValue::encode(jsUndefined());
857 }
858 #endif
859
860 EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
861 {
862     // We need this function for compatibility with the Mozilla JS tests but for now
863     // we don't actually do any version-specific handling
864     return JSValue::encode(jsUndefined());
865 }
866
867 EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
868 {
869     String fileName = exec->argument(0).toString(exec)->value(exec);
870     Vector<char> script;
871     if (!fillBufferWithContentsOfFile(fileName, script))
872         return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
873
874     GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
875
876     JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
877     for (unsigned i = 1; i < exec->argumentCount(); ++i)
878         array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
879     globalObject->putDirect(
880         exec->vm(), Identifier(globalObject->globalExec(), "arguments"), array);
881
882     JSValue exception;
883     StopWatch stopWatch;
884     stopWatch.start();
885     evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
886     stopWatch.stop();
887
888     if (!!exception) {
889         exec->vm().throwException(globalObject->globalExec(), exception);
890         return JSValue::encode(jsUndefined());
891     }
892     
893     return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
894 }
895
896 EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
897 {
898     String fileName = exec->argument(0).toString(exec)->value(exec);
899     Vector<char> script;
900     if (!fillBufferWithContentsOfFile(fileName, script))
901         return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
902
903     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
904     
905     JSValue evaluationException;
906     JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
907     if (evaluationException)
908         exec->vm().throwException(exec, evaluationException);
909     return JSValue::encode(result);
910 }
911
912 EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
913 {
914     String fileName = exec->argument(0).toString(exec)->value(exec);
915     Vector<char> script;
916     if (!fillBufferWithContentsOfFile(fileName, script))
917         return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
918
919     return JSValue::encode(jsString(exec, stringFromUTF(script.data())));
920 }
921
922 EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
923 {
924     String fileName = exec->argument(0).toString(exec)->value(exec);
925     Vector<char> script;
926     if (!fillBufferWithContentsOfFile(fileName, script))
927         return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
928
929     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
930
931     StopWatch stopWatch;
932     stopWatch.start();
933
934     JSValue syntaxException;
935     bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
936     stopWatch.stop();
937
938     if (!validSyntax)
939         exec->vm().throwException(exec, syntaxException);
940     return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
941 }
942
943 #if ENABLE(SAMPLING_FLAGS)
944 EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
945 {
946     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
947         unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
948         if ((flag >= 1) && (flag <= 32))
949             SamplingFlags::setFlag(flag);
950     }
951     return JSValue::encode(jsNull());
952 }
953
954 EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
955 {
956     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
957         unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
958         if ((flag >= 1) && (flag <= 32))
959             SamplingFlags::clearFlag(flag);
960     }
961     return JSValue::encode(jsNull());
962 }
963 #endif
964
965 EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
966 {
967     Vector<char, 256> line;
968     int c;
969     while ((c = getchar()) != EOF) {
970         // FIXME: Should we also break on \r? 
971         if (c == '\n')
972             break;
973         line.append(c);
974     }
975     line.append('\0');
976     return JSValue::encode(jsString(exec, line.data()));
977 }
978
979 EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
980 {
981     return JSValue::encode(jsNumber(currentTime()));
982 }
983
984 EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
985 {
986     return JSValue::encode(setNeverInline(exec));
987 }
988
989 EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
990 {
991     return JSValue::encode(optimizeNextInvocation(exec));
992 }
993
994 EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
995 {
996     return JSValue::encode(numberOfDFGCompiles(exec));
997 }
998
999 EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1000 {
1001     if (exec->argumentCount() < 1)
1002         return JSValue::encode(jsUndefined());
1003     
1004     CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1005     if (!block)
1006         return JSValue::encode(jsNumber(0));
1007     
1008     return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1009 }
1010
1011 EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1012 {
1013     if (exec->argumentCount() < 1)
1014         return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Not enough arguments")));
1015     
1016     JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1017     if (!buffer)
1018         return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Expected an array buffer")));
1019     
1020     ArrayBufferContents dummyContents;
1021     buffer->impl()->transfer(dummyContents);
1022     
1023     return JSValue::encode(jsUndefined());
1024 }
1025
1026 EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1027 {
1028     jscExit(EXIT_SUCCESS);
1029
1030 #if COMPILER(MSVC)
1031     // Without this, Visual Studio will complain that this method does not return a value.
1032     return JSValue::encode(jsUndefined());
1033 #endif
1034 }
1035
1036 EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1037 EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1038
1039 EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1040 EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1041
1042 EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1043
1044 EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1045 {
1046     return JSValue::encode(jsNumber(42));
1047 }
1048
1049 EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1050 {
1051     return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1052 }
1053
1054 EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1055 {
1056     JSValue value = exec->argument(0);
1057     if (value.isObject())
1058         return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1059     return JSValue::encode(jsBoolean(false));
1060 }
1061
1062 EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1063 {
1064     exec->vm().dumpTypeProfilerData();
1065     return JSValue::encode(jsUndefined());
1066 }
1067
1068 // Use SEH for Release builds only to get rid of the crash report dialog
1069 // (luckily the same tests fail in Release and Debug builds so far). Need to
1070 // be in a separate main function because the jscmain function requires object
1071 // unwinding.
1072
1073 #if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE)
1074 #define TRY       __try {
1075 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
1076 #else
1077 #define TRY
1078 #define EXCEPT(x)
1079 #endif
1080
1081 int jscmain(int argc, char** argv);
1082
1083 static double s_desiredTimeout;
1084
1085 static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
1086 {
1087     auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
1088     std::this_thread::sleep_for(timeout);
1089     
1090     dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
1091     CRASH();
1092 }
1093
1094 int main(int argc, char** argv)
1095 {
1096 #if PLATFORM(IOS) && CPU(ARM_THUMB2)
1097     // Enabled IEEE754 denormal support.
1098     fenv_t env;
1099     fegetenv( &env );
1100     env.__fpscr &= ~0x01000000u;
1101     fesetenv( &env );
1102 #endif
1103
1104 #if OS(WINDOWS)
1105 #if !OS(WINCE)
1106     // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1107     // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1108     // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1109     ::SetErrorMode(0);
1110
1111 #if defined(_DEBUG)
1112     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1113     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1114     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1115     _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1116     _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1117     _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1118 #endif
1119 #endif
1120
1121     timeBeginPeriod(1);
1122 #endif
1123
1124 #if PLATFORM(EFL)
1125     ecore_init();
1126 #endif
1127
1128     // Initialize JSC before getting VM.
1129 #if ENABLE(SAMPLING_REGIONS)
1130     WTF::initializeMainThread();
1131 #endif
1132     JSC::initializeThreading();
1133
1134 #if !OS(WINCE)
1135     if (char* timeoutString = getenv("JSC_timeout")) {
1136         if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
1137             dataLog(
1138                 "WARNING: timeout string is malformed, got ", timeoutString,
1139                 " but expected a number. Not using a timeout.\n");
1140         } else
1141             createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
1142     }
1143 #endif
1144
1145 #if PLATFORM(IOS)
1146     Options::crashIfCantAllocateJITMemory() = true;
1147 #endif
1148
1149     // We can't use destructors in the following code because it uses Windows
1150     // Structured Exception Handling
1151     int res = 0;
1152     TRY
1153         res = jscmain(argc, argv);
1154     EXCEPT(res = 3)
1155     if (Options::logHeapStatisticsAtExit())
1156         HeapStatistics::reportSuccess();
1157
1158 #if PLATFORM(EFL)
1159     ecore_shutdown();
1160 #endif
1161
1162     jscExit(res);
1163 }
1164
1165 static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
1166 {
1167     const char* script;
1168     String fileName;
1169     Vector<char> scriptBuffer;
1170
1171     if (dump)
1172         JSC::Options::dumpGeneratedBytecodes() = true;
1173
1174     VM& vm = globalObject->vm();
1175
1176 #if ENABLE(SAMPLING_FLAGS)
1177     SamplingFlags::start();
1178 #endif
1179
1180     bool success = true;
1181     for (size_t i = 0; i < scripts.size(); i++) {
1182         if (scripts[i].isFile) {
1183             fileName = scripts[i].argument;
1184             if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
1185                 return false; // fail early so we can catch missing files
1186             script = scriptBuffer.data();
1187         } else {
1188             script = scripts[i].argument;
1189             fileName = "[Command Line]";
1190         }
1191
1192         vm.startSampling();
1193
1194         JSValue evaluationException;
1195         JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
1196         success = success && !evaluationException;
1197         if (dump && !evaluationException)
1198             printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1199         if (evaluationException) {
1200             printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1201             Identifier stackID(globalObject->globalExec(), "stack");
1202             JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
1203             if (!stackValue.isUndefinedOrNull())
1204                 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1205         }
1206
1207         vm.stopSampling();
1208         globalObject->globalExec()->clearException();
1209     }
1210
1211 #if ENABLE(SAMPLING_FLAGS)
1212     SamplingFlags::stop();
1213 #endif
1214 #if ENABLE(SAMPLING_REGIONS)
1215     SamplingRegion::dump();
1216 #endif
1217     vm.dumpSampleData(globalObject->globalExec());
1218 #if ENABLE(SAMPLING_COUNTERS)
1219     AbstractSamplingCounter::dump();
1220 #endif
1221 #if ENABLE(REGEXP_TRACING)
1222     vm.dumpRegExpTrace();
1223 #endif
1224     return success;
1225 }
1226
1227 #define RUNNING_FROM_XCODE 0
1228
1229 static void runInteractive(GlobalObject* globalObject)
1230 {
1231     String interpreterName("Interpreter");
1232     
1233     bool shouldQuit = false;
1234     while (!shouldQuit) {
1235 #if HAVE(READLINE) && !RUNNING_FROM_XCODE
1236         ParserError error;
1237         String source;
1238         do {
1239             error = ParserError();
1240             char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
1241             shouldQuit = !line;
1242             if (!line)
1243                 break;
1244             source = source + line;
1245             source = source + '\n';
1246             checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
1247             if (!line[0])
1248                 break;
1249             add_history(line);
1250         } while (error.m_syntaxErrorType == ParserError::SyntaxErrorRecoverable);
1251         
1252         if (error.m_type != ParserError::ErrorNone) {
1253             printf("%s:%d\n", error.m_message.utf8().data(), error.m_line);
1254             continue;
1255         }
1256         
1257         
1258         JSValue evaluationException;
1259         JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
1260 #else
1261         printf("%s", interactivePrompt);
1262         Vector<char, 256> line;
1263         int c;
1264         while ((c = getchar()) != EOF) {
1265             // FIXME: Should we also break on \r? 
1266             if (c == '\n')
1267                 break;
1268             line.append(c);
1269         }
1270         if (line.isEmpty())
1271             break;
1272         line.append('\0');
1273
1274         JSValue evaluationException;
1275         JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
1276 #endif
1277         if (evaluationException)
1278             printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1279         else
1280             printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1281
1282         globalObject->globalExec()->clearException();
1283     }
1284     printf("\n");
1285 }
1286
1287 static NO_RETURN void printUsageStatement(bool help = false)
1288 {
1289     fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1290     fprintf(stderr, "  -d         Dumps bytecode (debug builds only)\n");
1291     fprintf(stderr, "  -e         Evaluate argument as script code\n");
1292     fprintf(stderr, "  -f         Specifies a source file (deprecated)\n");
1293     fprintf(stderr, "  -h|--help  Prints this help message\n");
1294     fprintf(stderr, "  -i         Enables interactive mode (default if no files are specified)\n");
1295 #if HAVE(SIGNAL_H)
1296     fprintf(stderr, "  -s         Installs signal handlers that exit on a crash (Unix platforms only)\n");
1297 #endif
1298     fprintf(stderr, "  -p <file>  Outputs profiling data to a file\n");
1299     fprintf(stderr, "  -x         Output exit code before terminating\n");
1300     fprintf(stderr, "\n");
1301     fprintf(stderr, "  --options                  Dumps all JSC VM options and exits\n");
1302     fprintf(stderr, "  --dumpOptions              Dumps all JSC VM options before continuing\n");
1303     fprintf(stderr, "  --<jsc VM option>=<value>  Sets the specified JSC VM option\n");
1304     fprintf(stderr, "\n");
1305
1306     jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1307 }
1308
1309 void CommandLine::parseArguments(int argc, char** argv)
1310 {
1311     int i = 1;
1312     bool needToDumpOptions = false;
1313     bool needToExit = false;
1314
1315     for (; i < argc; ++i) {
1316         const char* arg = argv[i];
1317         if (!strcmp(arg, "-f")) {
1318             if (++i == argc)
1319                 printUsageStatement();
1320             m_scripts.append(Script(true, argv[i]));
1321             continue;
1322         }
1323         if (!strcmp(arg, "-e")) {
1324             if (++i == argc)
1325                 printUsageStatement();
1326             m_scripts.append(Script(false, argv[i]));
1327             continue;
1328         }
1329         if (!strcmp(arg, "-i")) {
1330             m_interactive = true;
1331             continue;
1332         }
1333         if (!strcmp(arg, "-d")) {
1334             m_dump = true;
1335             continue;
1336         }
1337         if (!strcmp(arg, "-p")) {
1338             if (++i == argc)
1339                 printUsageStatement();
1340             m_profile = true;
1341             m_profilerOutput = argv[i];
1342             continue;
1343         }
1344         if (!strcmp(arg, "-s")) {
1345 #if HAVE(SIGNAL_H)
1346             signal(SIGILL, _exit);
1347             signal(SIGFPE, _exit);
1348             signal(SIGBUS, _exit);
1349             signal(SIGSEGV, _exit);
1350 #endif
1351             continue;
1352         }
1353         if (!strcmp(arg, "-x")) {
1354             m_exitCode = true;
1355             continue;
1356         }
1357         if (!strcmp(arg, "--")) {
1358             ++i;
1359             break;
1360         }
1361         if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1362             printUsageStatement(true);
1363
1364         if (!strcmp(arg, "--options")) {
1365             needToDumpOptions = true;
1366             needToExit = true;
1367             continue;
1368         }
1369         if (!strcmp(arg, "--dumpOptions")) {
1370             needToDumpOptions = true;
1371             continue;
1372         }
1373
1374         // See if the -- option is a JSC VM option.
1375         // NOTE: At this point, we know that the arg starts with "--". Skip it.
1376         if (JSC::Options::setOption(&arg[2])) {
1377             // The arg was recognized as a VM option and has been parsed.
1378             continue; // Just continue with the next arg. 
1379         }
1380
1381         // This arg is not recognized by the VM nor by jsc. Pass it on to the
1382         // script.
1383         m_scripts.append(Script(true, argv[i]));
1384     }
1385
1386     if (m_scripts.isEmpty())
1387         m_interactive = true;
1388
1389     for (; i < argc; ++i)
1390         m_arguments.append(argv[i]);
1391
1392     if (needToDumpOptions)
1393         JSC::Options::dumpAllOptions(stderr);
1394     if (needToExit)
1395         jscExit(EXIT_SUCCESS);
1396 }
1397
1398 int jscmain(int argc, char** argv)
1399 {
1400     // Note that the options parsing can affect VM creation, and thus
1401     // comes first.
1402     CommandLine options(argc, argv);
1403     VM* vm = VM::create(LargeHeap).leakRef();
1404     int result;
1405     {
1406         JSLockHolder locker(vm);
1407
1408         if (options.m_profile && !vm->m_perBytecodeProfiler)
1409             vm->m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*vm));
1410     
1411         GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
1412         bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
1413         if (options.m_interactive && success)
1414             runInteractive(globalObject);
1415
1416         result = success ? 0 : 3;
1417
1418         if (options.m_exitCode)
1419             printf("jsc exiting %d\n", result);
1420     
1421         if (options.m_profile) {
1422             if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
1423                 fprintf(stderr, "could not save profiler output.\n");
1424         }
1425         
1426 #if ENABLE(JIT)
1427         if (Options::enableExceptionFuzz())
1428             printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
1429 #endif
1430     }
1431     
1432     return result;
1433 }
1434
1435 static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1436 {
1437     FILE* f = fopen(fileName.utf8().data(), "r");
1438     if (!f) {
1439         fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1440         return false;
1441     }
1442
1443     size_t bufferSize = 0;
1444     size_t bufferCapacity = 1024;
1445
1446     buffer.resize(bufferCapacity);
1447
1448     while (!feof(f) && !ferror(f)) {
1449         bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
1450         if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
1451             bufferCapacity *= 2;
1452             buffer.resize(bufferCapacity);
1453         }
1454     }
1455     fclose(f);
1456     buffer[bufferSize] = '\0';
1457
1458     if (buffer[0] == '#' && buffer[1] == '!')
1459         buffer[0] = buffer[1] = '/';
1460
1461     return true;
1462 }