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

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

OSR exit should know about Int52 and Double constants
https://bugs.webkit.org/show_bug.cgi?id=131945

Reviewed by Oliver Hunt.

The DFG OSR exit machinery's ignorance would lead to some constants becoming
jsUndefined() after OSR exit.

The FTL OSR exit machinery's ignorance just meant that we would sometimes use a
stackmap constant rather than baking the constant into the OSRExit data structure.
So, not a big deal, but worth fixing.

Also added some helpful hacks to jsc.cpp for testing such OSR exit pathologies.

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsic):

  • dfg/DFGMinifiedNode.h:

(JSC::DFG::belongsInMinifiedGraph):
(JSC::DFG::MinifiedNode::hasConstantNumber):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument):

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionOtherFalse):
(functionUndefined):

  • runtime/Intrinsic.h:
  • tests/stress/fold-to-double-constant-then-exit.js: Added.

(foo):

  • tests/stress/fold-to-int52-constant-then-exit.js: Added.

(foo):

  • Property svn:eol-style set to native
File size: 38.1 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
222const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Element) };
223const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Masquerader) };
224const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Root) };
225
226ElementHandleOwner* Element::handleOwner()
227{
228 static ElementHandleOwner* owner = 0;
229 if (!owner)
230 owner = new ElementHandleOwner();
231 return owner;
232}
233
234void Element::finishCreation(VM& vm)
235{
236 Base::finishCreation(vm);
237 m_root->setElement(this);
238}
239
240}
241
242static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
243
244static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
245static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
246static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
247static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
248static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
249static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
250static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
251static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
252static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
253static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
254static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
255static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
256#ifndef NDEBUG
257static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
258static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
259#endif
260static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
261static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
262static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
263static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
264static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
265static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
266static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
267static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
268static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
269static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
270static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
271static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
272static EncodedJSValue JSC_HOST_CALL functionFalse(ExecState*);
273static EncodedJSValue JSC_HOST_CALL functionOtherFalse(ExecState*); // Need a separate function to break hash-consing of native executables.
274static EncodedJSValue JSC_HOST_CALL functionUndefined(ExecState*);
275static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
276static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
277
278#if ENABLE(SAMPLING_FLAGS)
279static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
280static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
281#endif
282
283struct Script {
284 bool isFile;
285 char* argument;
286
287 Script(bool isFile, char *argument)
288 : isFile(isFile)
289 , argument(argument)
290 {
291 }
292};
293
294class CommandLine {
295public:
296 CommandLine(int argc, char** argv)
297 : m_interactive(false)
298 , m_dump(false)
299 , m_exitCode(false)
300 , m_profile(false)
301 {
302 parseArguments(argc, argv);
303 }
304
305 bool m_interactive;
306 bool m_dump;
307 bool m_exitCode;
308 Vector<Script> m_scripts;
309 Vector<String> m_arguments;
310 bool m_profile;
311 String m_profilerOutput;
312
313 void parseArguments(int, char**);
314};
315
316static const char interactivePrompt[] = ">>> ";
317
318class StopWatch {
319public:
320 void start();
321 void stop();
322 long getElapsedMS(); // call stop() first
323
324private:
325 double m_startTime;
326 double m_stopTime;
327};
328
329void StopWatch::start()
330{
331 m_startTime = monotonicallyIncreasingTime();
332}
333
334void StopWatch::stop()
335{
336 m_stopTime = monotonicallyIncreasingTime();
337}
338
339long StopWatch::getElapsedMS()
340{
341 return static_cast<long>((m_stopTime - m_startTime) * 1000);
342}
343
344class GlobalObject : public JSGlobalObject {
345private:
346 GlobalObject(VM&, Structure*);
347
348public:
349 typedef JSGlobalObject Base;
350
351 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
352 {
353 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
354 object->finishCreation(vm, arguments);
355 vm.heap.addFinalizer(object, destroy);
356 return object;
357 }
358
359 static const bool needsDestruction = false;
360
361 DECLARE_INFO;
362 static const GlobalObjectMethodTable s_globalObjectMethodTable;
363
364 static Structure* createStructure(VM& vm, JSValue prototype)
365 {
366 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
367 }
368
369 static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
370
371protected:
372 void finishCreation(VM& vm, const Vector<String>& arguments)
373 {
374 Base::finishCreation(vm);
375
376 addFunction(vm, "debug", functionDebug, 1);
377 addFunction(vm, "describe", functionDescribe, 1);
378 addFunction(vm, "describeArray", functionDescribeArray, 1);
379 addFunction(vm, "print", functionPrint, 1);
380 addFunction(vm, "quit", functionQuit, 0);
381 addFunction(vm, "gc", functionGCAndSweep, 0);
382 addFunction(vm, "fullGC", functionFullGC, 0);
383 addFunction(vm, "edenGC", functionEdenGC, 0);
384#ifndef NDEBUG
385 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
386 addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
387#endif
388 addFunction(vm, "version", functionVersion, 1);
389 addFunction(vm, "run", functionRun, 1);
390 addFunction(vm, "load", functionLoad, 1);
391 addFunction(vm, "readFile", functionReadFile, 1);
392 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
393 addFunction(vm, "jscStack", functionJSCStack, 1);
394 addFunction(vm, "readline", functionReadline, 0);
395 addFunction(vm, "preciseTime", functionPreciseTime, 0);
396 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
397 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
398 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
399 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
400 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
401#if ENABLE(SAMPLING_FLAGS)
402 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
403 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
404#endif
405 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
406 addConstructableFunction(vm, "Element", functionCreateElement, 1);
407 addFunction(vm, "getElement", functionGetElement, 1);
408 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
409
410 putDirectNativeFunction(vm, this, Identifier(&vm, "DFGTrue"), 0, functionFalse, DFGTrueIntrinsic, DontEnum | JSC::Function);
411 putDirectNativeFunction(vm, this, Identifier(&vm, "OSRExit"), 0, functionUndefined, OSRExitIntrinsic, DontEnum | JSC::Function);
412 putDirectNativeFunction(vm, this, Identifier(&vm, "isFinalTier"), 0, functionOtherFalse, IsFinalTierIntrinsic, DontEnum | JSC::Function);
413
414 addFunction(vm, "effectful42", functionEffectful42, 0);
415 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
416
417 JSArray* array = constructEmptyArray(globalExec(), 0);
418 for (size_t i = 0; i < arguments.size(); ++i)
419 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
420 putDirect(vm, Identifier(globalExec(), "arguments"), array);
421
422 putDirect(vm, Identifier(globalExec(), "console"), jsUndefined());
423 }
424
425 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
426 {
427 Identifier identifier(&vm, name);
428 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
429 }
430
431 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
432 {
433 Identifier identifier(&vm, name);
434 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
435 }
436};
437
438const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
439const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0, &shouldInterruptScriptBeforeTimeout };
440
441
442GlobalObject::GlobalObject(VM& vm, Structure* structure)
443 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
444{
445}
446
447static inline String stringFromUTF(const char* utf8)
448{
449 // Find the the first non-ascii character, or nul.
450 const char* pos = utf8;
451 while (*pos > 0)
452 pos++;
453 size_t asciiLength = pos - utf8;
454
455 // Fast case - string is all ascii.
456 if (!*pos)
457 return String(utf8, asciiLength);
458
459 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
460 ASSERT(*pos < 0);
461 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
462 return String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
463}
464
465static inline SourceCode jscSource(const char* utf8, const String& filename)
466{
467 String str = stringFromUTF(utf8);
468 return makeSource(str, filename);
469}
470
471EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
472{
473 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
474 if (i)
475 putchar(' ');
476
477 printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data());
478 }
479
480 putchar('\n');
481 fflush(stdout);
482 return JSValue::encode(jsUndefined());
483}
484
485#ifndef NDEBUG
486EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
487{
488 if (!exec->callerFrame()->isVMEntrySentinel())
489 exec->vm().interpreter->dumpCallFrame(exec->callerFrame());
490 return JSValue::encode(jsUndefined());
491}
492#endif
493
494EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
495{
496 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
497 return JSValue::encode(jsUndefined());
498}
499
500EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
501{
502 if (exec->argumentCount() < 1)
503 return JSValue::encode(jsUndefined());
504 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
505}
506
507EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
508{
509 if (exec->argumentCount() < 1)
510 return JSValue::encode(jsUndefined());
511 JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
512 if (!object)
513 return JSValue::encode(jsString(exec, "<not object>"));
514 return JSValue::encode(jsString(exec, toString("<Public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
515}
516
517class FunctionJSCStackFunctor {
518public:
519 FunctionJSCStackFunctor(StringBuilder& trace)
520 : m_trace(trace)
521 {
522 }
523
524 StackVisitor::Status operator()(StackVisitor& visitor)
525 {
526 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
527 return StackVisitor::Continue;
528 }
529
530private:
531 StringBuilder& m_trace;
532};
533
534EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
535{
536 StringBuilder trace;
537 trace.appendLiteral("--> Stack trace:\n");
538
539 FunctionJSCStackFunctor functor(trace);
540 exec->iterate(functor);
541 fprintf(stderr, "%s", trace.toString().utf8().data());
542 return JSValue::encode(jsUndefined());
543}
544
545EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
546{
547 JSLockHolder lock(exec);
548 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
549}
550
551EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
552{
553 JSLockHolder lock(exec);
554 JSValue arg = exec->argument(0);
555 return JSValue::encode(Element::create(exec->vm(), exec->lexicalGlobalObject(), arg.isNull() ? nullptr : jsCast<Root*>(exec->argument(0))));
556}
557
558EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
559{
560 JSLockHolder lock(exec);
561 Element* result = jsCast<Root*>(exec->argument(0).asCell())->element();
562 return JSValue::encode(result ? result : jsUndefined());
563}
564
565EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
566{
567 JSLockHolder lock(exec);
568 Element* element = jsCast<Element*>(exec->argument(0));
569 Root* root = jsCast<Root*>(exec->argument(1));
570 element->setRoot(root);
571 return JSValue::encode(jsUndefined());
572}
573
574EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
575{
576 JSLockHolder lock(exec);
577 exec->heap()->collectAllGarbage();
578 return JSValue::encode(jsUndefined());
579}
580
581EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
582{
583 JSLockHolder lock(exec);
584 exec->heap()->collect(FullCollection);
585 return JSValue::encode(jsUndefined());
586}
587
588EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
589{
590 JSLockHolder lock(exec);
591 exec->heap()->collect(EdenCollection);
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 functionOtherFalse(ExecState*)
781{
782 return JSValue::encode(jsBoolean(false));
783}
784
785EncodedJSValue JSC_HOST_CALL functionUndefined(ExecState*)
786{
787 return JSValue::encode(jsUndefined());
788}
789
790EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
791{
792 return JSValue::encode(jsNumber(42));
793}
794
795EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
796{
797 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
798}
799
800// Use SEH for Release builds only to get rid of the crash report dialog
801// (luckily the same tests fail in Release and Debug builds so far). Need to
802// be in a separate main function because the jscmain function requires object
803// unwinding.
804
805#if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE)
806#define TRY __try {
807#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
808#else
809#define TRY
810#define EXCEPT(x)
811#endif
812
813int jscmain(int argc, char** argv);
814
815static double s_desiredTimeout;
816
817static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
818{
819 auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
820 std::this_thread::sleep_for(timeout);
821
822 dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
823 CRASH();
824}
825
826int main(int argc, char** argv)
827{
828#if PLATFORM(IOS) && CPU(ARM_THUMB2)
829 // Enabled IEEE754 denormal support.
830 fenv_t env;
831 fegetenv( &env );
832 env.__fpscr &= ~0x01000000u;
833 fesetenv( &env );
834#endif
835
836#if OS(WINDOWS)
837#if !OS(WINCE)
838 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
839 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
840 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
841 ::SetErrorMode(0);
842
843#if defined(_DEBUG)
844 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
845 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
846 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
847 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
848 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
849 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
850#endif
851#endif
852
853 timeBeginPeriod(1);
854#endif
855
856#if PLATFORM(EFL)
857 ecore_init();
858#endif
859
860 // Initialize JSC before getting VM.
861#if ENABLE(SAMPLING_REGIONS)
862 WTF::initializeMainThread();
863#endif
864 JSC::initializeThreading();
865
866#if !OS(WINCE)
867 if (char* timeoutString = getenv("JSC_timeout")) {
868 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
869 dataLog(
870 "WARNING: timeout string is malformed, got ", timeoutString,
871 " but expected a number. Not using a timeout.\n");
872 } else
873 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
874 }
875#endif
876
877#if PLATFORM(IOS)
878 Options::crashIfCantAllocateJITMemory() = true;
879#endif
880
881 // We can't use destructors in the following code because it uses Windows
882 // Structured Exception Handling
883 int res = 0;
884 TRY
885 res = jscmain(argc, argv);
886 EXCEPT(res = 3)
887 if (Options::logHeapStatisticsAtExit())
888 HeapStatistics::reportSuccess();
889
890#if PLATFORM(EFL)
891 ecore_shutdown();
892#endif
893
894 return res;
895}
896
897static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
898{
899 const char* script;
900 String fileName;
901 Vector<char> scriptBuffer;
902
903 if (dump)
904 JSC::Options::dumpGeneratedBytecodes() = true;
905
906 VM& vm = globalObject->vm();
907
908#if ENABLE(SAMPLING_FLAGS)
909 SamplingFlags::start();
910#endif
911
912 bool success = true;
913 for (size_t i = 0; i < scripts.size(); i++) {
914 if (scripts[i].isFile) {
915 fileName = scripts[i].argument;
916 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
917 return false; // fail early so we can catch missing files
918 script = scriptBuffer.data();
919 } else {
920 script = scripts[i].argument;
921 fileName = "[Command Line]";
922 }
923
924 vm.startSampling();
925
926 JSValue evaluationException;
927 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
928 success = success && !evaluationException;
929 if (dump && !evaluationException)
930 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
931 if (evaluationException) {
932 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
933 Identifier stackID(globalObject->globalExec(), "stack");
934 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
935 if (!stackValue.isUndefinedOrNull())
936 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
937 }
938
939 vm.stopSampling();
940 globalObject->globalExec()->clearException();
941 }
942
943#if ENABLE(SAMPLING_FLAGS)
944 SamplingFlags::stop();
945#endif
946#if ENABLE(SAMPLING_REGIONS)
947 SamplingRegion::dump();
948#endif
949 vm.dumpSampleData(globalObject->globalExec());
950#if ENABLE(SAMPLING_COUNTERS)
951 AbstractSamplingCounter::dump();
952#endif
953#if ENABLE(REGEXP_TRACING)
954 vm.dumpRegExpTrace();
955#endif
956 return success;
957}
958
959#define RUNNING_FROM_XCODE 0
960
961static void runInteractive(GlobalObject* globalObject)
962{
963 String interpreterName("Interpreter");
964
965 bool shouldQuit = false;
966 while (!shouldQuit) {
967#if HAVE(READLINE) && !RUNNING_FROM_XCODE
968 ParserError error;
969 String source;
970 do {
971 error = ParserError();
972 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
973 shouldQuit = !line;
974 if (!line)
975 break;
976 source = source + line;
977 source = source + '\n';
978 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
979 if (!line[0])
980 break;
981 add_history(line);
982 } while (error.m_syntaxErrorType == ParserError::SyntaxErrorRecoverable);
983
984 if (error.m_type != ParserError::ErrorNone) {
985 printf("%s:%d\n", error.m_message.utf8().data(), error.m_line);
986 continue;
987 }
988
989
990 JSValue evaluationException;
991 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
992#else
993 printf("%s", interactivePrompt);
994 Vector<char, 256> line;
995 int c;
996 while ((c = getchar()) != EOF) {
997 // FIXME: Should we also break on \r?
998 if (c == '\n')
999 break;
1000 line.append(c);
1001 }
1002 if (line.isEmpty())
1003 break;
1004 line.append('\0');
1005
1006 JSValue evaluationException;
1007 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
1008#endif
1009 if (evaluationException)
1010 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1011 else
1012 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1013
1014 globalObject->globalExec()->clearException();
1015 }
1016 printf("\n");
1017}
1018
1019static NO_RETURN void printUsageStatement(bool help = false)
1020{
1021 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1022 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
1023 fprintf(stderr, " -e Evaluate argument as script code\n");
1024 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
1025 fprintf(stderr, " -h|--help Prints this help message\n");
1026 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
1027#if HAVE(SIGNAL_H)
1028 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
1029#endif
1030 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
1031 fprintf(stderr, " -x Output exit code before terminating\n");
1032 fprintf(stderr, "\n");
1033 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
1034 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
1035 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
1036 fprintf(stderr, "\n");
1037
1038 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1039}
1040
1041void CommandLine::parseArguments(int argc, char** argv)
1042{
1043 int i = 1;
1044 bool needToDumpOptions = false;
1045 bool needToExit = false;
1046
1047 for (; i < argc; ++i) {
1048 const char* arg = argv[i];
1049 if (!strcmp(arg, "-f")) {
1050 if (++i == argc)
1051 printUsageStatement();
1052 m_scripts.append(Script(true, argv[i]));
1053 continue;
1054 }
1055 if (!strcmp(arg, "-e")) {
1056 if (++i == argc)
1057 printUsageStatement();
1058 m_scripts.append(Script(false, argv[i]));
1059 continue;
1060 }
1061 if (!strcmp(arg, "-i")) {
1062 m_interactive = true;
1063 continue;
1064 }
1065 if (!strcmp(arg, "-d")) {
1066 m_dump = true;
1067 continue;
1068 }
1069 if (!strcmp(arg, "-p")) {
1070 if (++i == argc)
1071 printUsageStatement();
1072 m_profile = true;
1073 m_profilerOutput = argv[i];
1074 continue;
1075 }
1076 if (!strcmp(arg, "-s")) {
1077#if HAVE(SIGNAL_H)
1078 signal(SIGILL, _exit);
1079 signal(SIGFPE, _exit);
1080 signal(SIGBUS, _exit);
1081 signal(SIGSEGV, _exit);
1082#endif
1083 continue;
1084 }
1085 if (!strcmp(arg, "-x")) {
1086 m_exitCode = true;
1087 continue;
1088 }
1089 if (!strcmp(arg, "--")) {
1090 ++i;
1091 break;
1092 }
1093 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1094 printUsageStatement(true);
1095
1096 if (!strcmp(arg, "--options")) {
1097 needToDumpOptions = true;
1098 needToExit = true;
1099 continue;
1100 }
1101 if (!strcmp(arg, "--dumpOptions")) {
1102 needToDumpOptions = true;
1103 continue;
1104 }
1105
1106 // See if the -- option is a JSC VM option.
1107 // NOTE: At this point, we know that the arg starts with "--". Skip it.
1108 if (JSC::Options::setOption(&arg[2])) {
1109 // The arg was recognized as a VM option and has been parsed.
1110 continue; // Just continue with the next arg.
1111 }
1112
1113 // This arg is not recognized by the VM nor by jsc. Pass it on to the
1114 // script.
1115 m_scripts.append(Script(true, argv[i]));
1116 }
1117
1118 if (m_scripts.isEmpty())
1119 m_interactive = true;
1120
1121 for (; i < argc; ++i)
1122 m_arguments.append(argv[i]);
1123
1124 if (needToDumpOptions)
1125 JSC::Options::dumpAllOptions(stderr);
1126 if (needToExit)
1127 exit(EXIT_SUCCESS);
1128}
1129
1130int jscmain(int argc, char** argv)
1131{
1132 // Note that the options parsing can affect VM creation, and thus
1133 // comes first.
1134 CommandLine options(argc, argv);
1135 VM* vm = VM::create(LargeHeap).leakRef();
1136 int result;
1137 {
1138 JSLockHolder locker(vm);
1139
1140 if (options.m_profile && !vm->m_perBytecodeProfiler)
1141 vm->m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*vm));
1142
1143 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
1144 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
1145 if (options.m_interactive && success)
1146 runInteractive(globalObject);
1147
1148 result = success ? 0 : 3;
1149
1150 if (options.m_exitCode)
1151 printf("jsc exiting %d\n", result);
1152
1153 if (options.m_profile) {
1154 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
1155 fprintf(stderr, "could not save profiler output.\n");
1156 }
1157 }
1158
1159 return result;
1160}
1161
1162static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1163{
1164 FILE* f = fopen(fileName.utf8().data(), "r");
1165 if (!f) {
1166 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1167 return false;
1168 }
1169
1170 size_t bufferSize = 0;
1171 size_t bufferCapacity = 1024;
1172
1173 buffer.resize(bufferCapacity);
1174
1175 while (!feof(f) && !ferror(f)) {
1176 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
1177 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
1178 bufferCapacity *= 2;
1179 buffer.resize(bufferCapacity);
1180 }
1181 }
1182 fclose(f);
1183 buffer[bufferSize] = '\0';
1184
1185 if (buffer[0] == '#' && buffer[1] == '!')
1186 buffer[0] = buffer[1] = '/';
1187
1188 return true;
1189}
Note: See TracBrowser for help on using the repository browser.