source: webkit/trunk/Source/JavaScriptCore/jsc.cpp@ 168510

Last change on this file since 168510 was 168510, checked in by [email protected], 11 years ago

Base case for get-by-id inline cache doesn't check for HasImpureGetOwnPropertySlot
https://bugs.webkit.org/show_bug.cgi?id=132695

Reviewed by Filip Pizlo.

We check in the case where we're accessing something other than the base object (e.g. the prototype),
but we fail to do so for the base object.

  • jit/Repatch.cpp:

(JSC::tryCacheGetByID):
(JSC::tryBuildGetByIDList):

  • jsc.cpp: Added some infrastructure to support this test. We don't currently trigger this bug anywhere in WebKit

because all of the values that are returned that could be impure are set to uncacheable anyways.
(WTF::ImpureGetter::ImpureGetter):
(WTF::ImpureGetter::createStructure):
(WTF::ImpureGetter::create):
(WTF::ImpureGetter::finishCreation):
(WTF::ImpureGetter::getOwnPropertySlot):
(WTF::ImpureGetter::visitChildren):
(WTF::ImpureGetter::setDelegate):
(GlobalObject::finishCreation):
(functionCreateImpureGetter):
(functionSetImpureGetterDelegate):

  • tests/stress/impure-get-own-property-slot-inline-cache.js: Added.

(foo):

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