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