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

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

Create tests for type profiling
https://bugs.webkit.org/show_bug.cgi?id=136161

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

The type profiler is now being tested. These are basic tests that don't
check every edge case, but will catch any major failures in the type profiler.
These tests cover:

  • The basic, inheritance-based type system in TypeSet.
  • Function return types.
  • Correct merging of types for multiple assignments to one variable.

This patch also provides an API for writing new tests for
the type profiler. The API works by passing in a function and a
unique substring of an expression contained in that function, and
returns an object representing type information for that expression.

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionFindTypeForExpression):
(functionReturnTypeFor):

  • runtime/TypeProfiler.cpp:

(JSC::TypeProfiler::typeInformationForExpressionAtOffset):

  • runtime/TypeProfiler.h:
  • runtime/TypeProfilerLog.h:
  • runtime/TypeSet.cpp:

(JSC::TypeSet::toJSONString):
(JSC::StructureShape::toJSONString):

  • runtime/TypeSet.h:
  • tests/typeProfiler: Added.
  • tests/typeProfiler.yaml: Added.
  • tests/typeProfiler/basic.js: Added.

(wrapper.foo):
(wrapper):

  • tests/typeProfiler/captured.js: Added.

(wrapper.changeFoo):
(wrapper):

  • tests/typeProfiler/driver: Added.
  • tests/typeProfiler/driver/driver.js: Added.

(assert):

  • tests/typeProfiler/inheritance.js: Added.

(wrapper.A):
(wrapper.B):
(wrapper.C):
(wrapper):

  • tests/typeProfiler/return.js: Added.

(foo):
(Ctor):

Tools:

Have run-javascriptcore-tests run the newly created
tests for the type profiler.

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