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

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

Unreviewed, rolling out r165926.
https://bugs.webkit.org/show_bug.cgi?id=130488

broke the iOS build (Requested by estes on #webkit).

Reverted changeset:

Source/JavaScriptCore:

"GC timer should intelligently choose between EdenCollections
and FullCollections"
https://bugs.webkit.org/show_bug.cgi?id=128261
http://trac.webkit.org/changeset/165926

Source/WebCore:

"GC timer should intelligently choose between EdenCollections
and FullCollections"
https://bugs.webkit.org/show_bug.cgi?id=128261
http://trac.webkit.org/changeset/165926

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