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

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

Need ability to fuzz exception throwing
https://bugs.webkit.org/show_bug.cgi?id=134945
<rdar://problem/17722027>

Reviewed by Sam Weinig.

Source/JavaScriptCore:
Adds the ability to instrument exception checks, and to force some random
exception check to artificially throw an exception. Also adds new tests that
are suitable for testing this. Note that this is closely tied to the Tools
directory changes that are also part of this changeset.

This also fixes an activation tear-off bug that arises if we ever throw an
exception from operationOptimize, or if due to some other bug it's only due
to the operationOptimize exception check that we realize that there is an
exception to be thrown.

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::fastExceptionCheck):

  • ftl/FTLIntrinsicRepository.h:
  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::callCheck):

  • interpreter/Interpreter.cpp:

(JSC::unwindCallFrame):

  • jit/AssemblyHelpers.cpp:

(JSC::AssemblyHelpers::callExceptionFuzz):
(JSC::AssemblyHelpers::emitExceptionCheck):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::emitExceptionCheck): Deleted.

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_enter):

  • jit/JITOperations.cpp:

(JSC::numberOfExceptionFuzzChecks):

  • jit/JITOperations.h:
  • jsc.cpp:

(jscmain):

  • runtime/Options.h:
  • runtime/TestRunnerUtils.h:
  • tests/exceptionFuzz.yaml: Added.
  • tests/exceptionFuzz: Added.
  • tests/exceptionFuzz/3d-cube.js: Added.
  • tests/exceptionFuzz/date-format-xparb.js: Added.
  • tests/exceptionFuzz/earley-boyer.js: Added.

Tools:
Adds a new script, js-exception-fuzz, which will run some jsc command-line using
exception fuzzing. This means that we will force exceptions to be thrown in random
places to see how the engine reacts. This is now integrated with the various test
drivers, so run-javascriptcore-tests will run some exception fuzzing tests by
default.

  • Scripts/jsc-stress-test-helpers/js-exception-fuzz: Added.

(fail):

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