]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | |
81345200 | 3 | * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 Apple Inc. All rights reserved. |
9dae56ea A |
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 | ||
81345200 | 25 | #include "ArrayPrototype.h" |
93a37866 | 26 | #include "ButterflyInlines.h" |
9dae56ea A |
27 | #include "BytecodeGenerator.h" |
28 | #include "Completion.h" | |
93a37866 | 29 | #include "CopiedSpaceInlines.h" |
14957cd0 | 30 | #include "ExceptionHelpers.h" |
93a37866 | 31 | #include "HeapStatistics.h" |
9dae56ea | 32 | #include "InitializeThreading.h" |
6fe7ccc8 | 33 | #include "Interpreter.h" |
9dae56ea | 34 | #include "JSArray.h" |
81345200 A |
35 | #include "JSArrayBuffer.h" |
36 | #include "JSCInlines.h" | |
ba379fdc | 37 | #include "JSFunction.h" |
9dae56ea | 38 | #include "JSLock.h" |
93a37866 | 39 | #include "JSProxy.h" |
f9bf01c6 | 40 | #include "JSString.h" |
81345200 | 41 | #include "ProfilerDatabase.h" |
9dae56ea | 42 | #include "SamplingTool.h" |
81345200 A |
43 | #include "StackVisitor.h" |
44 | #include "StructureInlines.h" | |
93a37866 | 45 | #include "StructureRareDataInlines.h" |
81345200 | 46 | #include "TestRunnerUtils.h" |
9dae56ea A |
47 | #include <math.h> |
48 | #include <stdio.h> | |
49 | #include <stdlib.h> | |
50 | #include <string.h> | |
81345200 | 51 | #include <thread> |
93a37866 A |
52 | #include <wtf/CurrentTime.h> |
53 | #include <wtf/MainThread.h> | |
54 | #include <wtf/StringPrintStream.h> | |
55 | #include <wtf/text/StringBuilder.h> | |
9dae56ea | 56 | |
f9bf01c6 | 57 | #if !OS(WINDOWS) |
9dae56ea A |
58 | #include <unistd.h> |
59 | #endif | |
60 | ||
61 | #if HAVE(READLINE) | |
6fe7ccc8 A |
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 | |
9dae56ea A |
65 | #include <readline/history.h> |
66 | #include <readline/readline.h> | |
6fe7ccc8 | 67 | #undef Function |
9dae56ea A |
68 | #endif |
69 | ||
70 | #if HAVE(SYS_TIME_H) | |
71 | #include <sys/time.h> | |
72 | #endif | |
73 | ||
ba379fdc | 74 | #if HAVE(SIGNAL_H) |
9dae56ea A |
75 | #include <signal.h> |
76 | #endif | |
77 | ||
f9bf01c6 | 78 | #if COMPILER(MSVC) && !OS(WINCE) |
9dae56ea | 79 | #include <crtdbg.h> |
ba379fdc | 80 | #include <mmsystem.h> |
f9bf01c6 | 81 | #include <windows.h> |
9dae56ea A |
82 | #endif |
83 | ||
93a37866 | 84 | #if PLATFORM(IOS) && CPU(ARM_THUMB2) |
6fe7ccc8 A |
85 | #include <fenv.h> |
86 | #include <arm/arch.h> | |
87 | #endif | |
88 | ||
93a37866 A |
89 | #if PLATFORM(EFL) |
90 | #include <Ecore.h> | |
91 | #endif | |
92 | ||
9dae56ea A |
93 | using namespace JSC; |
94 | using namespace WTF; | |
95 | ||
81345200 A |
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 | ||
93a37866 | 413 | static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer); |
9dae56ea | 414 | |
81345200 A |
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*); | |
14957cd0 A |
424 | static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*); |
425 | static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*); | |
93a37866 | 426 | static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*); |
81345200 | 427 | static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*); |
6fe7ccc8 | 428 | static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*); |
81345200 A |
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*); | |
14957cd0 A |
433 | #ifndef NDEBUG |
434 | static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*); | |
93a37866 | 435 | static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*); |
14957cd0 A |
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*); | |
81345200 | 440 | static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*); |
14957cd0 A |
441 | static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*); |
442 | static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*); | |
6fe7ccc8 | 443 | static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*); |
81345200 A |
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*); | |
14957cd0 | 449 | static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*); |
81345200 A |
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*); | |
ba379fdc A |
457 | |
458 | #if ENABLE(SAMPLING_FLAGS) | |
14957cd0 A |
459 | static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*); |
460 | static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*); | |
ba379fdc A |
461 | #endif |
462 | ||
463 | struct Script { | |
464 | bool isFile; | |
f9bf01c6 A |
465 | char* argument; |
466 | ||
ba379fdc A |
467 | Script(bool isFile, char *argument) |
468 | : isFile(isFile) | |
469 | , argument(argument) | |
470 | { | |
471 | } | |
472 | }; | |
9dae56ea | 473 | |
93a37866 A |
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) | |
9dae56ea | 481 | { |
93a37866 | 482 | parseArguments(argc, argv); |
9dae56ea A |
483 | } |
484 | ||
93a37866 A |
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**); | |
9dae56ea A |
494 | }; |
495 | ||
93a37866 | 496 | static const char interactivePrompt[] = ">>> "; |
9dae56ea A |
497 | |
498 | class StopWatch { | |
499 | public: | |
500 | void start(); | |
501 | void stop(); | |
502 | long getElapsedMS(); // call stop() first | |
503 | ||
504 | private: | |
f9bf01c6 A |
505 | double m_startTime; |
506 | double m_stopTime; | |
9dae56ea A |
507 | }; |
508 | ||
509 | void StopWatch::start() | |
510 | { | |
81345200 | 511 | m_startTime = monotonicallyIncreasingTime(); |
9dae56ea A |
512 | } |
513 | ||
514 | void StopWatch::stop() | |
515 | { | |
81345200 | 516 | m_stopTime = monotonicallyIncreasingTime(); |
9dae56ea A |
517 | } |
518 | ||
519 | long StopWatch::getElapsedMS() | |
520 | { | |
f9bf01c6 | 521 | return static_cast<long>((m_stopTime - m_startTime) * 1000); |
9dae56ea A |
522 | } |
523 | ||
524 | class GlobalObject : public JSGlobalObject { | |
6fe7ccc8 | 525 | private: |
93a37866 | 526 | GlobalObject(VM&, Structure*); |
6fe7ccc8 | 527 | |
9dae56ea | 528 | public: |
6fe7ccc8 A |
529 | typedef JSGlobalObject Base; |
530 | ||
93a37866 | 531 | static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments) |
6fe7ccc8 | 532 | { |
93a37866 A |
533 | GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure); |
534 | object->finishCreation(vm, arguments); | |
535 | vm.heap.addFinalizer(object, destroy); | |
6fe7ccc8 A |
536 | return object; |
537 | } | |
538 | ||
93a37866 A |
539 | static const bool needsDestruction = false; |
540 | ||
81345200 | 541 | DECLARE_INFO; |
93a37866 | 542 | static const GlobalObjectMethodTable s_globalObjectMethodTable; |
6fe7ccc8 | 543 | |
93a37866 | 544 | static Structure* createStructure(VM& vm, JSValue prototype) |
6fe7ccc8 | 545 | { |
81345200 | 546 | return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info()); |
6fe7ccc8 A |
547 | } |
548 | ||
93a37866 A |
549 | static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; } |
550 | ||
6fe7ccc8 | 551 | protected: |
93a37866 | 552 | void finishCreation(VM& vm, const Vector<String>& arguments) |
6fe7ccc8 | 553 | { |
93a37866 | 554 | Base::finishCreation(vm); |
6fe7ccc8 | 555 | |
93a37866 A |
556 | addFunction(vm, "debug", functionDebug, 1); |
557 | addFunction(vm, "describe", functionDescribe, 1); | |
81345200 | 558 | addFunction(vm, "describeArray", functionDescribeArray, 1); |
93a37866 A |
559 | addFunction(vm, "print", functionPrint, 1); |
560 | addFunction(vm, "quit", functionQuit, 0); | |
81345200 A |
561 | addFunction(vm, "gc", functionGCAndSweep, 0); |
562 | addFunction(vm, "fullGC", functionFullGC, 0); | |
563 | addFunction(vm, "edenGC", functionEdenGC, 0); | |
564 | addFunction(vm, "deleteAllCompiledCode", functionDeleteAllCompiledCode, 0); | |
6fe7ccc8 | 565 | #ifndef NDEBUG |
93a37866 A |
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); | |
81345200 | 572 | addFunction(vm, "readFile", functionReadFile, 1); |
93a37866 A |
573 | addFunction(vm, "checkSyntax", functionCheckSyntax, 1); |
574 | addFunction(vm, "jscStack", functionJSCStack, 1); | |
575 | addFunction(vm, "readline", functionReadline, 0); | |
576 | addFunction(vm, "preciseTime", functionPreciseTime, 0); | |
81345200 A |
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); | |
6fe7ccc8 | 583 | #if ENABLE(SAMPLING_FLAGS) |
93a37866 A |
584 | addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1); |
585 | addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1); | |
6fe7ccc8 | 586 | #endif |
81345200 A |
587 | addConstructableFunction(vm, "Root", functionCreateRoot, 0); |
588 | addConstructableFunction(vm, "Element", functionCreateElement, 1); | |
589 | addFunction(vm, "getElement", functionGetElement, 1); | |
590 | addFunction(vm, "setElementRoot", functionSetElementRoot, 2); | |
6fe7ccc8 | 591 | |
81345200 A |
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); | |
93a37866 | 603 | |
81345200 A |
604 | addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1); |
605 | addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2); | |
606 | ||
93a37866 | 607 | JSArray* array = constructEmptyArray(globalExec(), 0); |
6fe7ccc8 | 608 | for (size_t i = 0; i < arguments.size(); ++i) |
93a37866 A |
609 | array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i])); |
610 | putDirect(vm, Identifier(globalExec(), "arguments"), array); | |
81345200 A |
611 | |
612 | putDirect(vm, Identifier(globalExec(), "console"), jsUndefined()); | |
6fe7ccc8 A |
613 | } |
614 | ||
93a37866 | 615 | void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments) |
6fe7ccc8 | 616 | { |
81345200 A |
617 | Identifier identifier(&vm, name); |
618 | putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function)); | |
6fe7ccc8 A |
619 | } |
620 | ||
93a37866 | 621 | void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments) |
6fe7ccc8 | 622 | { |
81345200 A |
623 | Identifier identifier(&vm, name); |
624 | putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function)); | |
6fe7ccc8 | 625 | } |
9dae56ea | 626 | }; |
93a37866 | 627 | |
6fe7ccc8 | 628 | const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) }; |
81345200 | 629 | const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0, &shouldInterruptScriptBeforeTimeout }; |
93a37866 | 630 | |
6fe7ccc8 | 631 | |
93a37866 A |
632 | GlobalObject::GlobalObject(VM& vm, Structure* structure) |
633 | : JSGlobalObject(vm, structure, &s_globalObjectMethodTable) | |
9dae56ea | 634 | { |
6fe7ccc8 | 635 | } |
9dae56ea | 636 | |
93a37866 | 637 | static inline String stringFromUTF(const char* utf8) |
6fe7ccc8 A |
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; | |
93a37866 | 644 | |
6fe7ccc8 A |
645 | // Fast case - string is all ascii. |
646 | if (!*pos) | |
93a37866 A |
647 | return String(utf8, asciiLength); |
648 | ||
6fe7ccc8 A |
649 | // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback. |
650 | ASSERT(*pos < 0); | |
651 | ASSERT(strlen(utf8) == asciiLength + strlen(pos)); | |
93a37866 A |
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); | |
9dae56ea A |
659 | } |
660 | ||
14957cd0 | 661 | EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) |
9dae56ea | 662 | { |
14957cd0 | 663 | for (unsigned i = 0; i < exec->argumentCount(); ++i) { |
f9bf01c6 | 664 | if (i) |
9dae56ea | 665 | putchar(' '); |
f9bf01c6 | 666 | |
81345200 | 667 | printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data()); |
9dae56ea | 668 | } |
f9bf01c6 | 669 | |
9dae56ea A |
670 | putchar('\n'); |
671 | fflush(stdout); | |
14957cd0 | 672 | return JSValue::encode(jsUndefined()); |
9dae56ea A |
673 | } |
674 | ||
93a37866 A |
675 | #ifndef NDEBUG |
676 | EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec) | |
677 | { | |
81345200 | 678 | if (!exec->callerFrame()->isVMEntrySentinel()) |
93a37866 A |
679 | exec->vm().interpreter->dumpCallFrame(exec->callerFrame()); |
680 | return JSValue::encode(jsUndefined()); | |
681 | } | |
682 | #endif | |
683 | ||
14957cd0 | 684 | EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec) |
9dae56ea | 685 | { |
6fe7ccc8 A |
686 | fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data()); |
687 | return JSValue::encode(jsUndefined()); | |
688 | } | |
689 | ||
93a37866 A |
690 | EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec) |
691 | { | |
81345200 A |
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(), ">"))); | |
93a37866 A |
705 | } |
706 | ||
81345200 A |
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 | ||
6fe7ccc8 A |
724 | EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec) |
725 | { | |
93a37866 A |
726 | StringBuilder trace; |
727 | trace.appendLiteral("--> Stack trace:\n"); | |
728 | ||
81345200 A |
729 | FunctionJSCStackFunctor functor(trace); |
730 | exec->iterate(functor); | |
93a37866 | 731 | fprintf(stderr, "%s", trace.toString().utf8().data()); |
14957cd0 | 732 | return JSValue::encode(jsUndefined()); |
9dae56ea A |
733 | } |
734 | ||
81345200 A |
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) | |
9dae56ea | 810 | { |
6fe7ccc8 | 811 | JSLockHolder lock(exec); |
f9bf01c6 | 812 | exec->heap()->collectAllGarbage(); |
14957cd0 A |
813 | return JSValue::encode(jsUndefined()); |
814 | } | |
815 | ||
81345200 A |
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 | ||
14957cd0 A |
837 | #ifndef NDEBUG |
838 | EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec) | |
839 | { | |
6fe7ccc8 | 840 | JSLockHolder lock(exec); |
93a37866 | 841 | exec->vm().releaseExecutableMemory(); |
14957cd0 | 842 | return JSValue::encode(jsUndefined()); |
9dae56ea | 843 | } |
14957cd0 | 844 | #endif |
9dae56ea | 845 | |
14957cd0 | 846 | EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*) |
9dae56ea A |
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 | |
14957cd0 | 850 | return JSValue::encode(jsUndefined()); |
9dae56ea A |
851 | } |
852 | ||
14957cd0 | 853 | EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec) |
9dae56ea | 854 | { |
93a37866 | 855 | String fileName = exec->argument(0).toString(exec)->value(exec); |
9dae56ea A |
856 | Vector<char> script; |
857 | if (!fillBufferWithContentsOfFile(fileName, script)) | |
81345200 | 858 | return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file."))); |
9dae56ea | 859 | |
93a37866 | 860 | GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>()); |
9dae56ea | 861 | |
81345200 A |
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 | ||
6fe7ccc8 | 868 | JSValue exception; |
14957cd0 | 869 | StopWatch stopWatch; |
9dae56ea | 870 | stopWatch.start(); |
93a37866 | 871 | evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception); |
9dae56ea A |
872 | stopWatch.stop(); |
873 | ||
6fe7ccc8 | 874 | if (!!exception) { |
81345200 | 875 | exec->vm().throwException(globalObject->globalExec(), exception); |
6fe7ccc8 A |
876 | return JSValue::encode(jsUndefined()); |
877 | } | |
878 | ||
14957cd0 | 879 | return JSValue::encode(jsNumber(stopWatch.getElapsedMS())); |
9dae56ea A |
880 | } |
881 | ||
14957cd0 | 882 | EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec) |
9dae56ea | 883 | { |
93a37866 | 884 | String fileName = exec->argument(0).toString(exec)->value(exec); |
9dae56ea A |
885 | Vector<char> script; |
886 | if (!fillBufferWithContentsOfFile(fileName, script)) | |
81345200 | 887 | return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file."))); |
9dae56ea A |
888 | |
889 | JSGlobalObject* globalObject = exec->lexicalGlobalObject(); | |
6fe7ccc8 A |
890 | |
891 | JSValue evaluationException; | |
93a37866 | 892 | JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException); |
6fe7ccc8 | 893 | if (evaluationException) |
81345200 | 894 | exec->vm().throwException(exec, evaluationException); |
6fe7ccc8 | 895 | return JSValue::encode(result); |
ba379fdc | 896 | } |
9dae56ea | 897 | |
81345200 A |
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 | ||
14957cd0 | 908 | EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec) |
ba379fdc | 909 | { |
93a37866 | 910 | String fileName = exec->argument(0).toString(exec)->value(exec); |
ba379fdc A |
911 | Vector<char> script; |
912 | if (!fillBufferWithContentsOfFile(fileName, script)) | |
81345200 | 913 | return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file."))); |
ba379fdc A |
914 | |
915 | JSGlobalObject* globalObject = exec->lexicalGlobalObject(); | |
14957cd0 A |
916 | |
917 | StopWatch stopWatch; | |
918 | stopWatch.start(); | |
6fe7ccc8 A |
919 | |
920 | JSValue syntaxException; | |
921 | bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException); | |
14957cd0 A |
922 | stopWatch.stop(); |
923 | ||
6fe7ccc8 | 924 | if (!validSyntax) |
81345200 | 925 | exec->vm().throwException(exec, syntaxException); |
14957cd0 | 926 | return JSValue::encode(jsNumber(stopWatch.getElapsedMS())); |
9dae56ea A |
927 | } |
928 | ||
ba379fdc | 929 | #if ENABLE(SAMPLING_FLAGS) |
14957cd0 | 930 | EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec) |
ba379fdc | 931 | { |
14957cd0 | 932 | for (unsigned i = 0; i < exec->argumentCount(); ++i) { |
81345200 | 933 | unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec)); |
ba379fdc A |
934 | if ((flag >= 1) && (flag <= 32)) |
935 | SamplingFlags::setFlag(flag); | |
936 | } | |
14957cd0 | 937 | return JSValue::encode(jsNull()); |
ba379fdc A |
938 | } |
939 | ||
14957cd0 | 940 | EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec) |
ba379fdc | 941 | { |
14957cd0 | 942 | for (unsigned i = 0; i < exec->argumentCount(); ++i) { |
81345200 | 943 | unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec)); |
ba379fdc A |
944 | if ((flag >= 1) && (flag <= 32)) |
945 | SamplingFlags::clearFlag(flag); | |
946 | } | |
14957cd0 | 947 | return JSValue::encode(jsNull()); |
ba379fdc A |
948 | } |
949 | #endif | |
950 | ||
14957cd0 | 951 | EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec) |
9dae56ea A |
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'); | |
14957cd0 | 962 | return JSValue::encode(jsString(exec, line.data())); |
9dae56ea A |
963 | } |
964 | ||
6fe7ccc8 | 965 | EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*) |
9dae56ea | 966 | { |
6fe7ccc8 A |
967 | return JSValue::encode(jsNumber(currentTime())); |
968 | } | |
f9bf01c6 | 969 | |
81345200 A |
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 | ||
6fe7ccc8 A |
1012 | EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*) |
1013 | { | |
9dae56ea | 1014 | exit(EXIT_SUCCESS); |
f9bf01c6 A |
1015 | |
1016 | #if COMPILER(MSVC) && OS(WINCE) | |
1017 | // Without this, Visual Studio will complain that this method does not return a value. | |
14957cd0 | 1018 | return JSValue::encode(jsUndefined()); |
f9bf01c6 | 1019 | #endif |
9dae56ea A |
1020 | } |
1021 | ||
81345200 A |
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 | ||
9dae56ea A |
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 | ||
81345200 | 1045 | #if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE) |
9dae56ea A |
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 | ||
6fe7ccc8 | 1053 | int jscmain(int argc, char** argv); |
9dae56ea | 1054 | |
81345200 A |
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 | ||
9dae56ea A |
1066 | int main(int argc, char** argv) |
1067 | { | |
93a37866 | 1068 | #if PLATFORM(IOS) && CPU(ARM_THUMB2) |
6fe7ccc8 A |
1069 | // Enabled IEEE754 denormal support. |
1070 | fenv_t env; | |
1071 | fegetenv( &env ); | |
1072 | env.__fpscr &= ~0x01000000u; | |
1073 | fesetenv( &env ); | |
1074 | #endif | |
1075 | ||
14957cd0 A |
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); | |
14957cd0 A |
1082 | |
1083 | #if defined(_DEBUG) | |
9dae56ea A |
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 | |
93a37866 A |
1091 | #endif |
1092 | ||
81345200 | 1093 | timeBeginPeriod(1); |
9dae56ea A |
1094 | #endif |
1095 | ||
93a37866 A |
1096 | #if PLATFORM(EFL) |
1097 | ecore_init(); | |
1098 | #endif | |
1099 | ||
1100 | // Initialize JSC before getting VM. | |
81345200 | 1101 | #if ENABLE(SAMPLING_REGIONS) |
6fe7ccc8 | 1102 | WTF::initializeMainThread(); |
81345200 | 1103 | #endif |
9dae56ea A |
1104 | JSC::initializeThreading(); |
1105 | ||
81345200 A |
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 | ||
93a37866 A |
1117 | #if PLATFORM(IOS) |
1118 | Options::crashIfCantAllocateJITMemory() = true; | |
1119 | #endif | |
1120 | ||
9dae56ea A |
1121 | // We can't use destructors in the following code because it uses Windows |
1122 | // Structured Exception Handling | |
1123 | int res = 0; | |
9dae56ea | 1124 | TRY |
6fe7ccc8 | 1125 | res = jscmain(argc, argv); |
9dae56ea | 1126 | EXCEPT(res = 3) |
93a37866 A |
1127 | if (Options::logHeapStatisticsAtExit()) |
1128 | HeapStatistics::reportSuccess(); | |
1129 | ||
1130 | #if PLATFORM(EFL) | |
1131 | ecore_shutdown(); | |
1132 | #endif | |
1133 | ||
9dae56ea A |
1134 | return res; |
1135 | } | |
1136 | ||
ba379fdc | 1137 | static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump) |
9dae56ea | 1138 | { |
6fe7ccc8 | 1139 | const char* script; |
93a37866 | 1140 | String fileName; |
ba379fdc | 1141 | Vector<char> scriptBuffer; |
9dae56ea A |
1142 | |
1143 | if (dump) | |
93a37866 | 1144 | JSC::Options::dumpGeneratedBytecodes() = true; |
9dae56ea | 1145 | |
93a37866 | 1146 | VM& vm = globalObject->vm(); |
f9bf01c6 | 1147 | |
ba379fdc A |
1148 | #if ENABLE(SAMPLING_FLAGS) |
1149 | SamplingFlags::start(); | |
9dae56ea A |
1150 | #endif |
1151 | ||
1152 | bool success = true; | |
ba379fdc A |
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 | } | |
9dae56ea | 1163 | |
93a37866 | 1164 | vm.startSampling(); |
ba379fdc | 1165 | |
6fe7ccc8 | 1166 | JSValue evaluationException; |
93a37866 | 1167 | JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException); |
6fe7ccc8 A |
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()); | |
9dae56ea A |
1177 | } |
1178 | ||
93a37866 | 1179 | vm.stopSampling(); |
ba379fdc | 1180 | globalObject->globalExec()->clearException(); |
9dae56ea A |
1181 | } |
1182 | ||
ba379fdc A |
1183 | #if ENABLE(SAMPLING_FLAGS) |
1184 | SamplingFlags::stop(); | |
6fe7ccc8 A |
1185 | #endif |
1186 | #if ENABLE(SAMPLING_REGIONS) | |
1187 | SamplingRegion::dump(); | |
ba379fdc | 1188 | #endif |
93a37866 | 1189 | vm.dumpSampleData(globalObject->globalExec()); |
ba379fdc A |
1190 | #if ENABLE(SAMPLING_COUNTERS) |
1191 | AbstractSamplingCounter::dump(); | |
14957cd0 A |
1192 | #endif |
1193 | #if ENABLE(REGEXP_TRACING) | |
93a37866 | 1194 | vm.dumpRegExpTrace(); |
9dae56ea A |
1195 | #endif |
1196 | return success; | |
1197 | } | |
1198 | ||
ba379fdc A |
1199 | #define RUNNING_FROM_XCODE 0 |
1200 | ||
9dae56ea A |
1201 | static void runInteractive(GlobalObject* globalObject) |
1202 | { | |
93a37866 A |
1203 | String interpreterName("Interpreter"); |
1204 | ||
1205 | bool shouldQuit = false; | |
1206 | while (!shouldQuit) { | |
ba379fdc | 1207 | #if HAVE(READLINE) && !RUNNING_FROM_XCODE |
93a37866 A |
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; | |
9dae56ea | 1221 | add_history(line); |
93a37866 A |
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 | ||
6fe7ccc8 | 1230 | JSValue evaluationException; |
93a37866 | 1231 | JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException); |
9dae56ea | 1232 | #else |
ba379fdc | 1233 | printf("%s", interactivePrompt); |
9dae56ea A |
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 | } | |
ba379fdc A |
1242 | if (line.isEmpty()) |
1243 | break; | |
9dae56ea | 1244 | line.append('\0'); |
6fe7ccc8 A |
1245 | |
1246 | JSValue evaluationException; | |
93a37866 | 1247 | JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException); |
9dae56ea | 1248 | #endif |
6fe7ccc8 A |
1249 | if (evaluationException) |
1250 | printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data()); | |
9dae56ea | 1251 | else |
6fe7ccc8 | 1252 | printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data()); |
9dae56ea A |
1253 | |
1254 | globalObject->globalExec()->clearException(); | |
1255 | } | |
1256 | printf("\n"); | |
1257 | } | |
1258 | ||
6fe7ccc8 | 1259 | static NO_RETURN void printUsageStatement(bool help = false) |
9dae56ea A |
1260 | { |
1261 | fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n"); | |
1262 | fprintf(stderr, " -d Dumps bytecode (debug builds only)\n"); | |
ba379fdc | 1263 | fprintf(stderr, " -e Evaluate argument as script code\n"); |
9dae56ea A |
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"); | |
ba379fdc | 1267 | #if HAVE(SIGNAL_H) |
9dae56ea | 1268 | fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n"); |
ba379fdc | 1269 | #endif |
93a37866 A |
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"); | |
ba379fdc | 1277 | |
ba379fdc | 1278 | exit(help ? EXIT_SUCCESS : EXIT_FAILURE); |
9dae56ea A |
1279 | } |
1280 | ||
93a37866 | 1281 | void CommandLine::parseArguments(int argc, char** argv) |
9dae56ea A |
1282 | { |
1283 | int i = 1; | |
93a37866 A |
1284 | bool needToDumpOptions = false; |
1285 | bool needToExit = false; | |
1286 | ||
9dae56ea A |
1287 | for (; i < argc; ++i) { |
1288 | const char* arg = argv[i]; | |
f9bf01c6 | 1289 | if (!strcmp(arg, "-f")) { |
9dae56ea | 1290 | if (++i == argc) |
6fe7ccc8 | 1291 | printUsageStatement(); |
93a37866 | 1292 | m_scripts.append(Script(true, argv[i])); |
ba379fdc A |
1293 | continue; |
1294 | } | |
f9bf01c6 | 1295 | if (!strcmp(arg, "-e")) { |
ba379fdc | 1296 | if (++i == argc) |
6fe7ccc8 | 1297 | printUsageStatement(); |
93a37866 | 1298 | m_scripts.append(Script(false, argv[i])); |
9dae56ea A |
1299 | continue; |
1300 | } | |
f9bf01c6 | 1301 | if (!strcmp(arg, "-i")) { |
93a37866 | 1302 | m_interactive = true; |
9dae56ea A |
1303 | continue; |
1304 | } | |
f9bf01c6 | 1305 | if (!strcmp(arg, "-d")) { |
93a37866 A |
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]; | |
9dae56ea A |
1314 | continue; |
1315 | } | |
f9bf01c6 | 1316 | if (!strcmp(arg, "-s")) { |
ba379fdc | 1317 | #if HAVE(SIGNAL_H) |
9dae56ea A |
1318 | signal(SIGILL, _exit); |
1319 | signal(SIGFPE, _exit); | |
1320 | signal(SIGBUS, _exit); | |
1321 | signal(SIGSEGV, _exit); | |
1322 | #endif | |
1323 | continue; | |
1324 | } | |
93a37866 A |
1325 | if (!strcmp(arg, "-x")) { |
1326 | m_exitCode = true; | |
1327 | continue; | |
1328 | } | |
f9bf01c6 | 1329 | if (!strcmp(arg, "--")) { |
9dae56ea A |
1330 | ++i; |
1331 | break; | |
1332 | } | |
f9bf01c6 | 1333 | if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) |
6fe7ccc8 | 1334 | printUsageStatement(true); |
93a37866 A |
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])); | |
9dae56ea | 1356 | } |
f9bf01c6 | 1357 | |
93a37866 A |
1358 | if (m_scripts.isEmpty()) |
1359 | m_interactive = true; | |
f9bf01c6 | 1360 | |
9dae56ea | 1361 | for (; i < argc; ++i) |
93a37866 A |
1362 | m_arguments.append(argv[i]); |
1363 | ||
1364 | if (needToDumpOptions) | |
1365 | JSC::Options::dumpAllOptions(stderr); | |
1366 | if (needToExit) | |
1367 | exit(EXIT_SUCCESS); | |
9dae56ea A |
1368 | } |
1369 | ||
6fe7ccc8 | 1370 | int jscmain(int argc, char** argv) |
9dae56ea | 1371 | { |
93a37866 A |
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(); | |
93a37866 | 1376 | int result; |
81345200 A |
1377 | { |
1378 | JSLockHolder locker(vm); | |
93a37866 | 1379 | |
81345200 A |
1380 | if (options.m_profile && !vm->m_perBytecodeProfiler) |
1381 | vm->m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*vm)); | |
6fe7ccc8 | 1382 | |
81345200 A |
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); | |
9dae56ea | 1387 | |
81345200 | 1388 | result = success ? 0 : 3; |
9dae56ea | 1389 | |
81345200 A |
1390 | if (options.m_exitCode) |
1391 | printf("jsc exiting %d\n", result); | |
93a37866 | 1392 | |
81345200 A |
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 | |
93a37866 | 1402 | } |
81345200 | 1403 | |
93a37866 | 1404 | return result; |
9dae56ea A |
1405 | } |
1406 | ||
93a37866 | 1407 | static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer) |
9dae56ea | 1408 | { |
14957cd0 | 1409 | FILE* f = fopen(fileName.utf8().data(), "r"); |
9dae56ea | 1410 | if (!f) { |
14957cd0 | 1411 | fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data()); |
9dae56ea A |
1412 | return false; |
1413 | } | |
1414 | ||
f9bf01c6 A |
1415 | size_t bufferSize = 0; |
1416 | size_t bufferCapacity = 1024; | |
9dae56ea | 1417 | |
f9bf01c6 | 1418 | buffer.resize(bufferCapacity); |
9dae56ea A |
1419 | |
1420 | while (!feof(f) && !ferror(f)) { | |
f9bf01c6 A |
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); | |
9dae56ea A |
1425 | } |
1426 | } | |
1427 | fclose(f); | |
f9bf01c6 | 1428 | buffer[bufferSize] = '\0'; |
9dae56ea | 1429 | |
14957cd0 A |
1430 | if (buffer[0] == '#' && buffer[1] == '!') |
1431 | buffer[0] = buffer[1] = '/'; | |
1432 | ||
9dae56ea A |
1433 | return true; |
1434 | } |