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