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

Last change on this file since 195233 was 195233, checked in by Csaba Osztrogonác, 9 years ago

REGRESSION(r194601): Fix the jsc timeout option of jsc.cpp
https://bugs.webkit.org/show_bug.cgi?id=153204

Reviewed by Michael Catanzaro.

  • jsc.cpp:

(main):

  • Property svn:eol-style set to native
File size: 75.5 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004-2008, 2012-2013, 2015 Apple Inc. All rights reserved.
4 * Copyright (C) 2006 Bjoern Graf ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24
25#include "ArrayPrototype.h"
26#include "ButterflyInlines.h"
27#include "BytecodeGenerator.h"
28#include "CodeBlock.h"
29#include "Completion.h"
30#include "CopiedSpaceInlines.h"
31#include "DFGPlan.h"
32#include "Disassembler.h"
33#include "Exception.h"
34#include "ExceptionHelpers.h"
35#include "HeapStatistics.h"
36#include "InitializeThreading.h"
37#include "Interpreter.h"
38#include "JSArray.h"
39#include "JSArrayBuffer.h"
40#include "JSCInlines.h"
41#include "JSFunction.h"
42#include "JSInternalPromise.h"
43#include "JSInternalPromiseDeferred.h"
44#include "JSLock.h"
45#include "JSNativeStdFunction.h"
46#include "JSONObject.h"
47#include "JSProxy.h"
48#include "JSString.h"
49#include "JSWASMModule.h"
50#include "ProfilerDatabase.h"
51#include "SamplingProfiler.h"
52#include "SamplingTool.h"
53#include "StackVisitor.h"
54#include "StructureInlines.h"
55#include "StructureRareDataInlines.h"
56#include "TestRunnerUtils.h"
57#include "TypeProfilerLog.h"
58#include "WASMModuleParser.h"
59#include <math.h>
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63#include <thread>
64#include <wtf/CurrentTime.h>
65#include <wtf/MainThread.h>
66#include <wtf/StringPrintStream.h>
67#include <wtf/text/StringBuilder.h>
68
69#if OS(WINDOWS)
70#include <direct.h>
71#else
72#include <unistd.h>
73#endif
74
75#if HAVE(READLINE)
76// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
77// We #define it to something else to avoid this conflict.
78#define Function ReadlineFunction
79#include <readline/history.h>
80#include <readline/readline.h>
81#undef Function
82#endif
83
84#if HAVE(SYS_TIME_H)
85#include <sys/time.h>
86#endif
87
88#if HAVE(SIGNAL_H)
89#include <signal.h>
90#endif
91
92#if COMPILER(MSVC)
93#include <crtdbg.h>
94#include <mmsystem.h>
95#include <windows.h>
96#endif
97
98#if PLATFORM(IOS) && CPU(ARM_THUMB2)
99#include <fenv.h>
100#include <arm/arch.h>
101#endif
102
103#if PLATFORM(EFL)
104#include <Ecore.h>
105#endif
106
107using namespace JSC;
108using namespace WTF;
109
110namespace {
111
112NO_RETURN_WITH_VALUE static void jscExit(int status)
113{
114 waitForAsynchronousDisassembly();
115
116#if ENABLE(DFG_JIT)
117 if (DFG::isCrashing()) {
118 for (;;) {
119#if OS(WINDOWS)
120 Sleep(1000);
121#else
122 pause();
123#endif
124 }
125 }
126#endif // ENABLE(DFG_JIT)
127 exit(status);
128}
129
130class Element;
131class ElementHandleOwner;
132class Masuqerader;
133class Root;
134class RuntimeArray;
135
136class Element : public JSNonFinalObject {
137public:
138 Element(VM& vm, Structure* structure)
139 : Base(vm, structure)
140 {
141 }
142
143 typedef JSNonFinalObject Base;
144 static const bool needsDestruction = false;
145
146 Root* root() const { return m_root.get(); }
147 void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); }
148
149 static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
150 {
151 Structure* structure = createStructure(vm, globalObject, jsNull());
152 Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure);
153 element->finishCreation(vm, root);
154 return element;
155 }
156
157 void finishCreation(VM&, Root*);
158
159 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
160 {
161 Element* thisObject = jsCast<Element*>(cell);
162 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
163 Base::visitChildren(thisObject, visitor);
164 visitor.append(&thisObject->m_root);
165 }
166
167 static ElementHandleOwner* handleOwner();
168
169 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
170 {
171 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
172 }
173
174 DECLARE_INFO;
175
176private:
177 WriteBarrier<Root> m_root;
178};
179
180class ElementHandleOwner : public WeakHandleOwner {
181public:
182 virtual bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
183 {
184 Element* element = jsCast<Element*>(handle.slot()->asCell());
185 return visitor.containsOpaqueRoot(element->root());
186 }
187};
188
189class Masquerader : public JSNonFinalObject {
190public:
191 Masquerader(VM& vm, Structure* structure)
192 : Base(vm, structure)
193 {
194 }
195
196 typedef JSNonFinalObject Base;
197 static const unsigned StructureFlags = Base::StructureFlags | JSC::MasqueradesAsUndefined;
198
199 static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
200 {
201 globalObject->masqueradesAsUndefinedWatchpoint()->fireAll("Masquerading object allocated");
202 Structure* structure = createStructure(vm, globalObject, jsNull());
203 Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
204 result->finishCreation(vm);
205 return result;
206 }
207
208 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
209 {
210 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
211 }
212
213 DECLARE_INFO;
214};
215
216class Root : public JSDestructibleObject {
217public:
218 Root(VM& vm, Structure* structure)
219 : Base(vm, structure)
220 {
221 }
222
223 Element* element()
224 {
225 return m_element.get();
226 }
227
228 void setElement(Element* element)
229 {
230 Weak<Element> newElement(element, Element::handleOwner());
231 m_element.swap(newElement);
232 }
233
234 static Root* create(VM& vm, JSGlobalObject* globalObject)
235 {
236 Structure* structure = createStructure(vm, globalObject, jsNull());
237 Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
238 root->finishCreation(vm);
239 return root;
240 }
241
242 typedef JSDestructibleObject Base;
243
244 DECLARE_INFO;
245 static const bool needsDestruction = true;
246
247 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
248 {
249 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
250 }
251
252 static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
253 {
254 Base::visitChildren(thisObject, visitor);
255 visitor.addOpaqueRoot(thisObject);
256 }
257
258private:
259 Weak<Element> m_element;
260};
261
262class ImpureGetter : public JSNonFinalObject {
263public:
264 ImpureGetter(VM& vm, Structure* structure)
265 : Base(vm, structure)
266 {
267 }
268
269 DECLARE_INFO;
270 typedef JSNonFinalObject Base;
271 static const unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::OverridesGetOwnPropertySlot;
272
273 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
274 {
275 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
276 }
277
278 static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
279 {
280 ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
281 getter->finishCreation(vm, delegate);
282 return getter;
283 }
284
285 void finishCreation(VM& vm, JSObject* delegate)
286 {
287 Base::finishCreation(vm);
288 if (delegate)
289 m_delegate.set(vm, this, delegate);
290 }
291
292 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
293 {
294 ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
295
296 if (thisObject->m_delegate && thisObject->m_delegate->getPropertySlot(exec, name, slot))
297 return true;
298
299 return Base::getOwnPropertySlot(object, exec, name, slot);
300 }
301
302 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
303 {
304 Base::visitChildren(cell, visitor);
305 ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell);
306 visitor.append(&thisObject->m_delegate);
307 }
308
309 void setDelegate(VM& vm, JSObject* delegate)
310 {
311 m_delegate.set(vm, this, delegate);
312 }
313
314private:
315 WriteBarrier<JSObject> m_delegate;
316};
317
318class CustomGetter : public JSNonFinalObject {
319public:
320 CustomGetter(VM& vm, Structure* structure)
321 : Base(vm, structure)
322 {
323 }
324
325 DECLARE_INFO;
326 typedef JSNonFinalObject Base;
327 static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot;
328
329 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
330 {
331 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
332 }
333
334 static CustomGetter* create(VM& vm, Structure* structure)
335 {
336 CustomGetter* getter = new (NotNull, allocateCell<CustomGetter>(vm.heap, sizeof(CustomGetter))) CustomGetter(vm, structure);
337 getter->finishCreation(vm);
338 return getter;
339 }
340
341 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
342 {
343 CustomGetter* thisObject = jsCast<CustomGetter*>(object);
344 if (propertyName == PropertyName(Identifier::fromString(exec, "customGetter"))) {
345 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->customGetter);
346 return true;
347 }
348 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
349 }
350
351private:
352 static EncodedJSValue customGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
353 {
354 CustomGetter* thisObject = jsDynamicCast<CustomGetter*>(JSValue::decode(thisValue));
355 if (!thisObject)
356 return throwVMTypeError(exec);
357 bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow"))).toBoolean(exec);
358 if (shouldThrow)
359 return throwVMTypeError(exec);
360 return JSValue::encode(jsNumber(100));
361 }
362};
363
364class RuntimeArray : public JSArray {
365public:
366 typedef JSArray Base;
367 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
368
369 static RuntimeArray* create(ExecState* exec)
370 {
371 VM& vm = exec->vm();
372 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
373 Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
374 RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
375 runtimeArray->finishCreation(exec);
376 vm.heap.addFinalizer(runtimeArray, destroy);
377 return runtimeArray;
378 }
379
380 ~RuntimeArray() { }
381
382 static void destroy(JSCell* cell)
383 {
384 static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
385 }
386
387 static const bool needsDestruction = false;
388
389 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
390 {
391 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
392 if (propertyName == exec->propertyNames().length) {
393 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
394 return true;
395 }
396
397 Optional<uint32_t> index = parseIndex(propertyName);
398 if (index && index.value() < thisObject->getLength()) {
399 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
400 return true;
401 }
402
403 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
404 }
405
406 static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
407 {
408 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
409 if (index < thisObject->getLength()) {
410 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
411 return true;
412 }
413
414 return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
415 }
416
417 static NO_RETURN_DUE_TO_CRASH void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
418 {
419 RELEASE_ASSERT_NOT_REACHED();
420 }
421
422 static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
423 {
424 RELEASE_ASSERT_NOT_REACHED();
425 }
426
427 unsigned getLength() const { return m_vector.size(); }
428
429 DECLARE_INFO;
430
431 static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
432 {
433 return globalObject->arrayPrototype();
434 }
435
436 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
437 {
438 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
439 }
440
441protected:
442 void finishCreation(ExecState* exec)
443 {
444 Base::finishCreation(exec->vm());
445 ASSERT(inherits(info()));
446
447 for (size_t i = 0; i < exec->argumentCount(); i++)
448 m_vector.append(exec->argument(i).toInt32(exec));
449 }
450
451private:
452 RuntimeArray(ExecState* exec, Structure* structure)
453 : JSArray(exec->vm(), structure, 0)
454 {
455 }
456
457 static EncodedJSValue lengthGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
458 {
459 RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
460 if (!thisObject)
461 return throwVMTypeError(exec);
462 return JSValue::encode(jsNumber(thisObject->getLength()));
463 }
464
465 Vector<int> m_vector;
466};
467
468const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
469const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
470const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
471const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
472const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
473const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
474
475ElementHandleOwner* Element::handleOwner()
476{
477 static ElementHandleOwner* owner = 0;
478 if (!owner)
479 owner = new ElementHandleOwner();
480 return owner;
481}
482
483void Element::finishCreation(VM& vm, Root* root)
484{
485 Base::finishCreation(vm);
486 setRoot(vm, root);
487 m_root->setElement(this);
488}
489
490}
491
492static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
493
494static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
495static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
496static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
497static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
498static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
499
500static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
501static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
502static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
503static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
504static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
505static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
506static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
507static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
508static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
509static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
510static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
511static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
512static EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*);
513static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*);
514static EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState*);
515#ifndef NDEBUG
516static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
517#endif
518static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
519static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
520static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
521static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
522static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
523static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
524static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
525static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
526static EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState*);
527static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
528static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
529static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
530static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
531static EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState*);
532static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
533static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*);
534static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
535static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
536static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
537static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
538static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
539static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
540static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
541static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
542static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
543static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
544static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
545static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
546static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
547static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
548static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*);
549static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*);
550static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*);
551static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*);
552#if ENABLE(WEBASSEMBLY)
553static EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState*);
554#endif
555static EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState*);
556static EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState*);
557static EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*);
558#if ENABLE(SAMPLING_PROFILER)
559static EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState*);
560static EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState*);
561#endif
562
563#if ENABLE(SAMPLING_FLAGS)
564static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
565static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
566#endif
567
568struct Script {
569 bool isFile;
570 char* argument;
571
572 Script(bool isFile, char *argument)
573 : isFile(isFile)
574 , argument(argument)
575 {
576 }
577};
578
579class CommandLine {
580public:
581 CommandLine(int argc, char** argv)
582 {
583 parseArguments(argc, argv);
584 }
585
586 bool m_interactive { false };
587 bool m_dump { false };
588 bool m_module { false };
589 bool m_exitCode { false };
590 Vector<Script> m_scripts;
591 Vector<String> m_arguments;
592 bool m_profile { false };
593 String m_profilerOutput;
594
595 void parseArguments(int, char**);
596};
597
598static const char interactivePrompt[] = ">>> ";
599
600class StopWatch {
601public:
602 void start();
603 void stop();
604 long getElapsedMS(); // call stop() first
605
606private:
607 double m_startTime;
608 double m_stopTime;
609};
610
611void StopWatch::start()
612{
613 m_startTime = monotonicallyIncreasingTime();
614}
615
616void StopWatch::stop()
617{
618 m_stopTime = monotonicallyIncreasingTime();
619}
620
621long StopWatch::getElapsedMS()
622{
623 return static_cast<long>((m_stopTime - m_startTime) * 1000);
624}
625
626template<typename Vector>
627static inline String stringFromUTF(const Vector& utf8)
628{
629 return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size());
630}
631
632template<typename Vector>
633static inline SourceCode jscSource(const Vector& utf8, const String& filename)
634{
635 String str = stringFromUTF(utf8);
636 return makeSource(str, filename);
637}
638
639class GlobalObject : public JSGlobalObject {
640private:
641 GlobalObject(VM&, Structure*);
642
643public:
644 typedef JSGlobalObject Base;
645
646 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
647 {
648 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
649 object->finishCreation(vm, arguments);
650 vm.heap.addFinalizer(object, destroy);
651 return object;
652 }
653
654 static const bool needsDestruction = false;
655
656 DECLARE_INFO;
657 static const GlobalObjectMethodTable s_globalObjectMethodTable;
658
659 static Structure* createStructure(VM& vm, JSValue prototype)
660 {
661 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
662 }
663
664 static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags::createAllEnabled(); }
665
666protected:
667 void finishCreation(VM& vm, const Vector<String>& arguments)
668 {
669 Base::finishCreation(vm);
670
671 addFunction(vm, "debug", functionDebug, 1);
672 addFunction(vm, "describe", functionDescribe, 1);
673 addFunction(vm, "describeArray", functionDescribeArray, 1);
674 addFunction(vm, "print", functionPrint, 1);
675 addFunction(vm, "quit", functionQuit, 0);
676 addFunction(vm, "abort", functionAbort, 0);
677 addFunction(vm, "gc", functionGCAndSweep, 0);
678 addFunction(vm, "fullGC", functionFullGC, 0);
679 addFunction(vm, "edenGC", functionEdenGC, 0);
680 addFunction(vm, "forceGCSlowPaths", functionForceGCSlowPaths, 0);
681 addFunction(vm, "gcHeapSize", functionHeapSize, 0);
682 addFunction(vm, "addressOf", functionAddressOf, 1);
683#ifndef NDEBUG
684 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
685#endif
686 addFunction(vm, "version", functionVersion, 1);
687 addFunction(vm, "run", functionRun, 1);
688 addFunction(vm, "load", functionLoad, 1);
689 addFunction(vm, "readFile", functionReadFile, 1);
690 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
691 addFunction(vm, "jscStack", functionJSCStack, 1);
692 addFunction(vm, "readline", functionReadline, 0);
693 addFunction(vm, "preciseTime", functionPreciseTime, 0);
694 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
695 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
696 addFunction(vm, "noDFG", functionNoDFG, 1);
697 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
698 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
699 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
700 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
701 addFunction(vm, "failNextNewCodeBlock", functionFailNextNewCodeBlock, 1);
702#if ENABLE(SAMPLING_FLAGS)
703 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
704 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
705#endif
706 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
707 addConstructableFunction(vm, "Element", functionCreateElement, 1);
708 addFunction(vm, "getElement", functionGetElement, 1);
709 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
710
711 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum);
712 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum);
713 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum);
714 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum);
715 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, DontEnum);
716 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum);
717
718 addFunction(vm, "effectful42", functionEffectful42, 0);
719 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
720 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
721
722 addFunction(vm, "createProxy", functionCreateProxy, 1);
723 addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
724
725 addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
726 addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
727 addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
728
729 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
730 addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
731 addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
732
733 addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
734 addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
735 addFunction(vm, "basicBlockExecutionCount", functionBasicBlockExecutionCount, 2);
736
737 addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
738
739 addFunction(vm, "drainMicrotasks", functionDrainMicrotasks, 0);
740
741 addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
742
743#if ENABLE(WEBASSEMBLY)
744 addFunction(vm, "loadWebAssembly", functionLoadWebAssembly, 3);
745#endif
746 addFunction(vm, "loadModule", functionLoadModule, 1);
747 addFunction(vm, "checkModuleSyntax", functionCheckModuleSyntax, 1);
748
749 addFunction(vm, "platformSupportsSamplingProfiler", functionPlatformSupportsSamplingProfiler, 0);
750#if ENABLE(SAMPLING_PROFILER)
751 addFunction(vm, "startSamplingProfiler", functionStartSamplingProfiler, 0);
752 addFunction(vm, "samplingProfilerStackTraces", functionSamplingProfilerStackTraces, 0);
753#endif
754
755 JSArray* array = constructEmptyArray(globalExec(), 0);
756 for (size_t i = 0; i < arguments.size(); ++i)
757 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
758 putDirect(vm, Identifier::fromString(globalExec(), "arguments"), array);
759
760 putDirect(vm, Identifier::fromString(globalExec(), "console"), jsUndefined());
761 }
762
763 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
764 {
765 Identifier identifier = Identifier::fromString(&vm, name);
766 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
767 }
768
769 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
770 {
771 Identifier identifier = Identifier::fromString(&vm, name);
772 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
773 }
774
775 static JSInternalPromise* moduleLoaderResolve(JSGlobalObject*, ExecState*, JSValue, JSValue);
776 static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSValue);
777};
778
779const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, nullptr, CREATE_METHOD_TABLE(GlobalObject) };
780const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, nullptr };
781
782
783GlobalObject::GlobalObject(VM& vm, Structure* structure)
784 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
785{
786}
787
788static UChar pathSeparator()
789{
790#if OS(WINDOWS)
791 return '\\';
792#else
793 return '/';
794#endif
795}
796
797struct DirectoryName {
798 // In unix, it is "/". In Windows, it becomes a drive letter like "C:\"
799 String rootName;
800
801 // If the directory name is "/home/WebKit", this becomes "home/WebKit". If the directory name is "/", this becomes "".
802 String queryName;
803};
804
805struct ModuleName {
806 ModuleName(const String& moduleName);
807
808 bool startsWithRoot() const
809 {
810 return !queries.isEmpty() && queries[0].isEmpty();
811 }
812
813 Vector<String> queries;
814};
815
816ModuleName::ModuleName(const String& moduleName)
817{
818 // A module name given from code is represented as the UNIX style path. Like, `./A/B.js`.
819 moduleName.split('/', true, queries);
820}
821
822static bool extractDirectoryName(const String& absolutePathToFile, DirectoryName& directoryName)
823{
824 size_t firstSeparatorPosition = absolutePathToFile.find(pathSeparator());
825 if (firstSeparatorPosition == notFound)
826 return false;
827 directoryName.rootName = absolutePathToFile.substring(0, firstSeparatorPosition + 1); // Include the separator.
828 size_t lastSeparatorPosition = absolutePathToFile.reverseFind(pathSeparator());
829 ASSERT_WITH_MESSAGE(lastSeparatorPosition != notFound, "If the separator is not found, this function already returns when performing the forward search.");
830 if (firstSeparatorPosition == lastSeparatorPosition)
831 directoryName.queryName = StringImpl::empty();
832 else {
833 size_t queryStartPosition = firstSeparatorPosition + 1;
834 size_t queryLength = lastSeparatorPosition - queryStartPosition; // Not include the last separator.
835 directoryName.queryName = absolutePathToFile.substring(queryStartPosition, queryLength);
836 }
837 return true;
838}
839
840static bool currentWorkingDirectory(DirectoryName& directoryName)
841{
842#if OS(WINDOWS)
843 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364934.aspx
844 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
845 // The _MAX_PATH in Windows is 260. If the path of the current working directory is longer than that, _getcwd truncates the result.
846 // And other I/O functions taking a path name also truncate it. To avoid this situation,
847 //
848 // (1). When opening the file in Windows for modules, we always use the abosolute path and add "\\?\" prefix to the path name.
849 // (2). When retrieving the current working directory, use GetCurrentDirectory instead of _getcwd.
850 //
851 // In the path utility functions inside the JSC shell, we does not handle the UNC and UNCW including the network host name.
852 DWORD bufferLength = ::GetCurrentDirectoryW(0, nullptr);
853 if (!bufferLength)
854 return false;
855 // In Windows, wchar_t is the UTF-16LE.
856 // https://msdn.microsoft.com/en-us/library/dd374081.aspx
857 // https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407.aspx
858 auto buffer = std::make_unique<wchar_t[]>(bufferLength);
859 DWORD lengthNotIncludingNull = ::GetCurrentDirectoryW(bufferLength, buffer.get());
860 static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
861 String directoryString = String(reinterpret_cast<UChar*>(buffer.get()));
862 // We don't support network path like \\host\share\<path name>.
863 if (directoryString.startsWith("\\\\"))
864 return false;
865#else
866 auto buffer = std::make_unique<char[]>(PATH_MAX);
867 if (!getcwd(buffer.get(), PATH_MAX))
868 return false;
869 String directoryString = String::fromUTF8(buffer.get());
870#endif
871 if (directoryString.isEmpty())
872 return false;
873
874 if (directoryString[directoryString.length() - 1] == pathSeparator())
875 return extractDirectoryName(directoryString, directoryName);
876 // Append the seperator to represents the file name. extractDirectoryName only accepts the absolute file name.
877 return extractDirectoryName(makeString(directoryString, pathSeparator()), directoryName);
878}
879
880static String resolvePath(const DirectoryName& directoryName, const ModuleName& moduleName)
881{
882 Vector<String> directoryPieces;
883 directoryName.queryName.split(pathSeparator(), false, directoryPieces);
884
885 // Only first '/' is recognized as the path from the root.
886 if (moduleName.startsWithRoot())
887 directoryPieces.clear();
888
889 for (const auto& query : moduleName.queries) {
890 if (query == String(ASCIILiteral(".."))) {
891 if (!directoryPieces.isEmpty())
892 directoryPieces.removeLast();
893 } else if (!query.isEmpty() && query != String(ASCIILiteral(".")))
894 directoryPieces.append(query);
895 }
896
897 StringBuilder builder;
898 builder.append(directoryName.rootName);
899 for (size_t i = 0; i < directoryPieces.size(); ++i) {
900 builder.append(directoryPieces[i]);
901 if (i + 1 != directoryPieces.size())
902 builder.append(pathSeparator());
903 }
904 return builder.toString();
905}
906
907JSInternalPromise* GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSValue keyValue, JSValue referrerValue)
908{
909 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
910 const Identifier key = keyValue.toPropertyKey(exec);
911 if (exec->hadException()) {
912 JSValue exception = exec->exception();
913 exec->clearException();
914 return deferred->reject(exec, exception);
915 }
916
917 if (key.isSymbol())
918 return deferred->resolve(exec, keyValue);
919
920 DirectoryName directoryName;
921 if (referrerValue.isUndefined()) {
922 if (!currentWorkingDirectory(directoryName))
923 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
924 } else {
925 const Identifier referrer = referrerValue.toPropertyKey(exec);
926 if (exec->hadException()) {
927 JSValue exception = exec->exception();
928 exec->clearException();
929 return deferred->reject(exec, exception);
930 }
931 if (referrer.isSymbol()) {
932 if (!currentWorkingDirectory(directoryName))
933 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
934 } else {
935 // If the referrer exists, we assume that the referrer is the correct absolute path.
936 if (!extractDirectoryName(referrer.impl(), directoryName))
937 return deferred->reject(exec, createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
938 }
939 }
940
941 return deferred->resolve(exec, jsString(exec, resolvePath(directoryName, ModuleName(key.impl()))));
942}
943
944static void convertShebangToJSComment(Vector<char>& buffer)
945{
946 if (buffer.size() >= 2) {
947 if (buffer[0] == '#' && buffer[1] == '!')
948 buffer[0] = buffer[1] = '/';
949 }
950}
951
952static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
953{
954 fseek(file, 0, SEEK_END);
955 size_t bufferCapacity = ftell(file);
956 fseek(file, 0, SEEK_SET);
957 buffer.resize(bufferCapacity);
958 size_t readSize = fread(buffer.data(), 1, buffer.size(), file);
959 return readSize == buffer.size();
960}
961
962static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
963{
964 FILE* f = fopen(fileName.utf8().data(), "rb");
965 if (!f) {
966 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
967 return false;
968 }
969
970 bool result = fillBufferWithContentsOfFile(f, buffer);
971 fclose(f);
972
973 return result;
974}
975
976static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
977{
978 if (!fillBufferWithContentsOfFile(fileName, buffer))
979 return false;
980 convertShebangToJSComment(buffer);
981 return true;
982}
983
984static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
985{
986 // We assume that fileName is always an absolute path.
987#if OS(WINDOWS)
988 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
989 // Use long UNC to pass the long path name to the Windows APIs.
990 String longUNCPathName = WTF::makeString("\\\\?\\", fileName);
991 static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
992 auto utf16Vector = longUNCPathName.charactersWithNullTermination();
993 FILE* f = _wfopen(reinterpret_cast<wchar_t*>(utf16Vector.data()), L"rb");
994#else
995 FILE* f = fopen(fileName.utf8().data(), "r");
996#endif
997 if (!f) {
998 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
999 return false;
1000 }
1001
1002 bool result = fillBufferWithContentsOfFile(f, buffer);
1003 if (result)
1004 convertShebangToJSComment(buffer);
1005 fclose(f);
1006
1007 return result;
1008}
1009
1010JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, ExecState* exec, JSValue key)
1011{
1012 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1013 String moduleKey = key.toString(exec)->value(exec);
1014 if (exec->hadException()) {
1015 JSValue exception = exec->exception();
1016 exec->clearException();
1017 return deferred->reject(exec, exception);
1018 }
1019
1020 // Here, now we consider moduleKey as the fileName.
1021 Vector<char> utf8;
1022 if (!fetchModuleFromLocalFileSystem(moduleKey, utf8))
1023 return deferred->reject(exec, createError(exec, makeString("Could not open file '", moduleKey, "'.")));
1024
1025 return deferred->resolve(exec, jsString(exec, stringFromUTF(utf8)));
1026}
1027
1028
1029EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
1030{
1031 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1032 if (i)
1033 putchar(' ');
1034
1035 printf("%s", exec->uncheckedArgument(i).toString(exec)->view(exec).get().utf8().data());
1036 }
1037
1038 putchar('\n');
1039 fflush(stdout);
1040 return JSValue::encode(jsUndefined());
1041}
1042
1043#ifndef NDEBUG
1044EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
1045{
1046 VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
1047 ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
1048 if (callerFrame)
1049 exec->vm().interpreter->dumpCallFrame(callerFrame);
1050 return JSValue::encode(jsUndefined());
1051}
1052#endif
1053
1054EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
1055{
1056 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->view(exec).get().utf8().data());
1057 return JSValue::encode(jsUndefined());
1058}
1059
1060EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
1061{
1062 if (exec->argumentCount() < 1)
1063 return JSValue::encode(jsUndefined());
1064 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
1065}
1066
1067EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
1068{
1069 if (exec->argumentCount() < 1)
1070 return JSValue::encode(jsUndefined());
1071 JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
1072 if (!object)
1073 return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
1074 return JSValue::encode(jsNontrivialString(exec, toString("<Public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
1075}
1076
1077class FunctionJSCStackFunctor {
1078public:
1079 FunctionJSCStackFunctor(StringBuilder& trace)
1080 : m_trace(trace)
1081 {
1082 }
1083
1084 StackVisitor::Status operator()(StackVisitor& visitor)
1085 {
1086 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
1087 return StackVisitor::Continue;
1088 }
1089
1090private:
1091 StringBuilder& m_trace;
1092};
1093
1094EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
1095{
1096 StringBuilder trace;
1097 trace.appendLiteral("--> Stack trace:\n");
1098
1099 FunctionJSCStackFunctor functor(trace);
1100 exec->iterate(functor);
1101 fprintf(stderr, "%s", trace.toString().utf8().data());
1102 return JSValue::encode(jsUndefined());
1103}
1104
1105EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
1106{
1107 JSLockHolder lock(exec);
1108 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
1109}
1110
1111EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
1112{
1113 JSLockHolder lock(exec);
1114 JSValue arg = exec->argument(0);
1115 return JSValue::encode(Element::create(exec->vm(), exec->lexicalGlobalObject(), arg.isNull() ? nullptr : jsCast<Root*>(exec->argument(0))));
1116}
1117
1118EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
1119{
1120 JSLockHolder lock(exec);
1121 Element* result = jsCast<Root*>(exec->argument(0).asCell())->element();
1122 return JSValue::encode(result ? result : jsUndefined());
1123}
1124
1125EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
1126{
1127 JSLockHolder lock(exec);
1128 Element* element = jsCast<Element*>(exec->argument(0));
1129 Root* root = jsCast<Root*>(exec->argument(1));
1130 element->setRoot(exec->vm(), root);
1131 return JSValue::encode(jsUndefined());
1132}
1133
1134EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
1135{
1136 JSLockHolder lock(exec);
1137 JSValue target = exec->argument(0);
1138 if (!target.isObject())
1139 return JSValue::encode(jsUndefined());
1140 JSObject* jsTarget = asObject(target.asCell());
1141 Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->prototype());
1142 JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
1143 return JSValue::encode(proxy);
1144}
1145
1146EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
1147{
1148 JSLockHolder lock(exec);
1149 RuntimeArray* array = RuntimeArray::create(exec);
1150 return JSValue::encode(array);
1151}
1152
1153EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
1154{
1155 JSLockHolder lock(exec);
1156 JSValue target = exec->argument(0);
1157 JSObject* delegate = nullptr;
1158 if (target.isObject())
1159 delegate = asObject(target.asCell());
1160 Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1161 ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
1162 return JSValue::encode(result);
1163}
1164
1165EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec)
1166{
1167 JSLockHolder lock(exec);
1168 Structure* structure = CustomGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1169 CustomGetter* result = CustomGetter::create(exec->vm(), structure);
1170 return JSValue::encode(result);
1171}
1172
1173EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
1174{
1175 JSLockHolder lock(exec);
1176 JSValue base = exec->argument(0);
1177 if (!base.isObject())
1178 return JSValue::encode(jsUndefined());
1179 JSValue delegate = exec->argument(1);
1180 if (!delegate.isObject())
1181 return JSValue::encode(jsUndefined());
1182 ImpureGetter* impureGetter = jsCast<ImpureGetter*>(asObject(base.asCell()));
1183 impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));
1184 return JSValue::encode(jsUndefined());
1185}
1186
1187EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
1188{
1189 JSLockHolder lock(exec);
1190 exec->heap()->collectAllGarbage();
1191 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1192}
1193
1194EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
1195{
1196 JSLockHolder lock(exec);
1197 exec->heap()->collect(FullCollection);
1198 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1199}
1200
1201EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
1202{
1203 JSLockHolder lock(exec);
1204 exec->heap()->collect(EdenCollection);
1205 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastEdenCollection()));
1206}
1207
1208EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*)
1209{
1210 // It's best for this to be the first thing called in the
1211 // JS program so the option is set to true before we JIT.
1212 Options::forceGCSlowPaths() = true;
1213 return JSValue::encode(jsUndefined());
1214}
1215
1216EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
1217{
1218 JSLockHolder lock(exec);
1219 return JSValue::encode(jsNumber(exec->heap()->size()));
1220}
1221
1222// This function is not generally very helpful in 64-bit code as the tag and payload
1223// share a register. But in 32-bit JITed code the tag may not be checked if an
1224// optimization removes type checking requirements, such as in ===.
1225EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState* exec)
1226{
1227 JSValue value = exec->argument(0);
1228 if (!value.isCell())
1229 return JSValue::encode(jsUndefined());
1230 // Need to cast to uint64_t so bitwise_cast will play along.
1231 uint64_t asNumber = reinterpret_cast<uint64_t>(value.asCell());
1232 EncodedJSValue returnValue = JSValue::encode(jsNumber(bitwise_cast<double>(asNumber)));
1233 return returnValue;
1234}
1235
1236EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
1237{
1238 // We need this function for compatibility with the Mozilla JS tests but for now
1239 // we don't actually do any version-specific handling
1240 return JSValue::encode(jsUndefined());
1241}
1242
1243EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
1244{
1245 String fileName = exec->argument(0).toString(exec)->value(exec);
1246 Vector<char> script;
1247 if (!fetchScriptFromLocalFileSystem(fileName, script))
1248 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
1249
1250 GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
1251
1252 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
1253 for (unsigned i = 1; i < exec->argumentCount(); ++i)
1254 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
1255 globalObject->putDirect(
1256 exec->vm(), Identifier::fromString(globalObject->globalExec(), "arguments"), array);
1257
1258 NakedPtr<Exception> exception;
1259 StopWatch stopWatch;
1260 stopWatch.start();
1261 evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), exception);
1262 stopWatch.stop();
1263
1264 if (exception) {
1265 exec->vm().throwException(globalObject->globalExec(), exception);
1266 return JSValue::encode(jsUndefined());
1267 }
1268
1269 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
1270}
1271
1272EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
1273{
1274 String fileName = exec->argument(0).toString(exec)->value(exec);
1275 Vector<char> script;
1276 if (!fetchScriptFromLocalFileSystem(fileName, script))
1277 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
1278
1279 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1280
1281 NakedPtr<Exception> evaluationException;
1282 JSValue result = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), evaluationException);
1283 if (evaluationException)
1284 exec->vm().throwException(exec, evaluationException);
1285 return JSValue::encode(result);
1286}
1287
1288EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
1289{
1290 String fileName = exec->argument(0).toString(exec)->value(exec);
1291 Vector<char> script;
1292 if (!fillBufferWithContentsOfFile(fileName, script))
1293 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
1294
1295 return JSValue::encode(jsString(exec, stringFromUTF(script)));
1296}
1297
1298EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
1299{
1300 String fileName = exec->argument(0).toString(exec)->value(exec);
1301 Vector<char> script;
1302 if (!fetchScriptFromLocalFileSystem(fileName, script))
1303 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
1304
1305 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1306
1307 StopWatch stopWatch;
1308 stopWatch.start();
1309
1310 JSValue syntaxException;
1311 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, fileName), &syntaxException);
1312 stopWatch.stop();
1313
1314 if (!validSyntax)
1315 exec->vm().throwException(exec, syntaxException);
1316 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
1317}
1318
1319#if ENABLE(SAMPLING_FLAGS)
1320EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
1321{
1322 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1323 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
1324 if ((flag >= 1) && (flag <= 32))
1325 SamplingFlags::setFlag(flag);
1326 }
1327 return JSValue::encode(jsNull());
1328}
1329
1330EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
1331{
1332 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1333 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
1334 if ((flag >= 1) && (flag <= 32))
1335 SamplingFlags::clearFlag(flag);
1336 }
1337 return JSValue::encode(jsNull());
1338}
1339#endif
1340
1341EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
1342{
1343 Vector<char, 256> line;
1344 int c;
1345 while ((c = getchar()) != EOF) {
1346 // FIXME: Should we also break on \r?
1347 if (c == '\n')
1348 break;
1349 line.append(c);
1350 }
1351 line.append('\0');
1352 return JSValue::encode(jsString(exec, line.data()));
1353}
1354
1355EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
1356{
1357 return JSValue::encode(jsNumber(currentTime()));
1358}
1359
1360EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
1361{
1362 return JSValue::encode(setNeverInline(exec));
1363}
1364
1365EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState* exec)
1366{
1367 return JSValue::encode(setNeverOptimize(exec));
1368}
1369
1370EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
1371{
1372 return JSValue::encode(optimizeNextInvocation(exec));
1373}
1374
1375EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
1376{
1377 return JSValue::encode(numberOfDFGCompiles(exec));
1378}
1379
1380EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1381{
1382 if (exec->argumentCount() < 1)
1383 return JSValue::encode(jsUndefined());
1384
1385 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1386 if (!block)
1387 return JSValue::encode(jsNumber(0));
1388
1389 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1390}
1391
1392EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1393{
1394 if (exec->argumentCount() < 1)
1395 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Not enough arguments"))));
1396
1397 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1398 if (!buffer)
1399 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Expected an array buffer"))));
1400
1401 ArrayBufferContents dummyContents;
1402 buffer->impl()->transfer(dummyContents);
1403
1404 return JSValue::encode(jsUndefined());
1405}
1406
1407EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState* exec)
1408{
1409 exec->vm().setFailNextNewCodeBlock();
1410 return JSValue::encode(jsUndefined());
1411}
1412
1413EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1414{
1415 jscExit(EXIT_SUCCESS);
1416
1417#if COMPILER(MSVC)
1418 // Without this, Visual Studio will complain that this method does not return a value.
1419 return JSValue::encode(jsUndefined());
1420#endif
1421}
1422
1423EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*)
1424{
1425 CRASH();
1426}
1427
1428EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1429EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1430
1431EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1432EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1433EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
1434{
1435 for (size_t i = 0; i < exec->argumentCount(); ++i) {
1436 if (!exec->argument(i).isInt32())
1437 return JSValue::encode(jsBoolean(false));
1438 }
1439 return JSValue::encode(jsBoolean(true));
1440}
1441
1442EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1443
1444EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1445{
1446 return JSValue::encode(jsNumber(42));
1447}
1448
1449EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1450{
1451 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1452}
1453
1454EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1455{
1456 JSValue value = exec->argument(0);
1457 if (value.isObject())
1458 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1459 return JSValue::encode(jsBoolean(false));
1460}
1461
1462EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1463{
1464 exec->vm().dumpTypeProfilerData();
1465 return JSValue::encode(jsUndefined());
1466}
1467
1468EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
1469{
1470 RELEASE_ASSERT(exec->vm().typeProfiler());
1471 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
1472
1473 JSValue functionValue = exec->argument(0);
1474 RELEASE_ASSERT(functionValue.isFunction());
1475 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1476
1477 RELEASE_ASSERT(exec->argument(1).isString());
1478 String substring = exec->argument(1).getString(exec);
1479 String sourceCodeText = executable->source().view().toString();
1480 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
1481
1482 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
1483 return JSValue::encode(JSONParse(exec, jsonString));
1484}
1485
1486EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
1487{
1488 RELEASE_ASSERT(exec->vm().typeProfiler());
1489 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
1490
1491 JSValue functionValue = exec->argument(0);
1492 RELEASE_ASSERT(functionValue.isFunction());
1493 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1494
1495 unsigned offset = executable->typeProfilingStartOffset();
1496 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
1497 return JSValue::encode(JSONParse(exec, jsonString));
1498}
1499
1500EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
1501{
1502 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1503 exec->vm().controlFlowProfiler()->dumpData();
1504 return JSValue::encode(jsUndefined());
1505}
1506
1507EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
1508{
1509 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1510
1511 JSValue functionValue = exec->argument(0);
1512 RELEASE_ASSERT(functionValue.isFunction());
1513 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1514
1515 RELEASE_ASSERT(exec->argument(1).isString());
1516 String substring = exec->argument(1).getString(exec);
1517 String sourceCodeText = executable->source().view().toString();
1518 RELEASE_ASSERT(sourceCodeText.contains(substring));
1519 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
1520
1521 bool hasExecuted = exec->vm().controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), exec->vm());
1522 return JSValue::encode(jsBoolean(hasExecuted));
1523}
1524
1525EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec)
1526{
1527 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1528
1529 JSValue functionValue = exec->argument(0);
1530 RELEASE_ASSERT(functionValue.isFunction());
1531 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1532
1533 RELEASE_ASSERT(exec->argument(1).isString());
1534 String substring = exec->argument(1).getString(exec);
1535 String sourceCodeText = executable->source().view().toString();
1536 RELEASE_ASSERT(sourceCodeText.contains(substring));
1537 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
1538
1539 size_t executionCount = exec->vm().controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), exec->vm());
1540 return JSValue::encode(JSValue(executionCount));
1541}
1542
1543EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
1544{
1545 Options::useExceptionFuzz() = true;
1546 return JSValue::encode(jsUndefined());
1547}
1548
1549EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState* exec)
1550{
1551 exec->vm().drainMicrotasks();
1552 return JSValue::encode(jsUndefined());
1553}
1554
1555EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*)
1556{
1557#if USE(JSVALUE64)
1558 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
1559#else
1560 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
1561#endif
1562}
1563
1564#if ENABLE(WEBASSEMBLY)
1565EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState* exec)
1566{
1567 String fileName = exec->argument(0).toString(exec)->value(exec);
1568 Vector<char> buffer;
1569 if (!fillBufferWithContentsOfFile(fileName, buffer))
1570 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
1571 RefPtr<WebAssemblySourceProvider> sourceProvider = WebAssemblySourceProvider::create(reinterpret_cast<Vector<uint8_t>&>(buffer), fileName);
1572 SourceCode source(sourceProvider);
1573 JSObject* imports = exec->argument(1).getObject();
1574 JSArrayBuffer* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(2));
1575
1576 String errorMessage;
1577 JSWASMModule* module = parseWebAssembly(exec, source, imports, arrayBuffer, errorMessage);
1578 if (!module)
1579 return JSValue::encode(exec->vm().throwException(exec, createSyntaxError(exec, errorMessage)));
1580 return JSValue::encode(module);
1581}
1582#endif
1583
1584EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
1585{
1586 String fileName = exec->argument(0).toString(exec)->value(exec);
1587 Vector<char> script;
1588 if (!fetchScriptFromLocalFileSystem(fileName, script))
1589 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
1590
1591 JSInternalPromise* promise = loadAndEvaluateModule(exec, fileName);
1592 if (exec->hadException())
1593 return JSValue::encode(jsUndefined());
1594
1595 JSValue error;
1596 JSFunction* errorHandler = JSNativeStdFunction::create(exec->vm(), exec->lexicalGlobalObject(), 1, String(), [&](ExecState* exec) {
1597 error = exec->argument(0);
1598 return JSValue::encode(jsUndefined());
1599 });
1600
1601 promise->then(exec, nullptr, errorHandler);
1602 exec->vm().drainMicrotasks();
1603 if (error)
1604 return JSValue::encode(exec->vm().throwException(exec, error));
1605 return JSValue::encode(jsUndefined());
1606}
1607
1608EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState* exec)
1609{
1610 String source = exec->argument(0).toString(exec)->value(exec);
1611
1612 StopWatch stopWatch;
1613 stopWatch.start();
1614
1615 ParserError error;
1616 bool validSyntax = checkModuleSyntax(exec, makeSource(source), error);
1617 stopWatch.stop();
1618
1619 if (!validSyntax)
1620 exec->vm().throwException(exec, jsNontrivialString(exec, toString("SyntaxError: ", error.message(), ":", error.line())));
1621 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
1622}
1623
1624EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*)
1625{
1626#if ENABLE(SAMPLING_PROFILER)
1627 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
1628#else
1629 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
1630#endif
1631}
1632
1633#if ENABLE(SAMPLING_PROFILER)
1634EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState* exec)
1635{
1636 exec->vm().ensureSamplingProfiler(WTF::Stopwatch::create());
1637 exec->vm().samplingProfiler()->noticeCurrentThreadAsJSCExecutionThread();
1638 exec->vm().samplingProfiler()->start();
1639 return JSValue::encode(jsUndefined());
1640}
1641
1642EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState* exec)
1643{
1644 RELEASE_ASSERT(exec->vm().samplingProfiler());
1645 String jsonString = exec->vm().samplingProfiler()->stacktracesAsJSON();
1646 exec->vm().samplingProfiler()->clearData();
1647 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
1648 RELEASE_ASSERT(!exec->hadException());
1649 return result;
1650}
1651#endif // ENABLE(SAMPLING_PROFILER)
1652
1653// Use SEH for Release builds only to get rid of the crash report dialog
1654// (luckily the same tests fail in Release and Debug builds so far). Need to
1655// be in a separate main function because the jscmain function requires object
1656// unwinding.
1657
1658#if COMPILER(MSVC) && !defined(_DEBUG)
1659#define TRY __try {
1660#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
1661#else
1662#define TRY
1663#define EXCEPT(x)
1664#endif
1665
1666int jscmain(int argc, char** argv);
1667
1668static double s_desiredTimeout;
1669
1670static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
1671{
1672 auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
1673 std::this_thread::sleep_for(timeout);
1674
1675 dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
1676 CRASH();
1677}
1678
1679int main(int argc, char** argv)
1680{
1681#if PLATFORM(IOS) && CPU(ARM_THUMB2)
1682 // Enabled IEEE754 denormal support.
1683 fenv_t env;
1684 fegetenv( &env );
1685 env.__fpscr &= ~0x01000000u;
1686 fesetenv( &env );
1687#endif
1688
1689#if OS(WINDOWS) && (defined(_M_X64) || defined(__x86_64__))
1690 // The VS2013 runtime has a bug where it mis-detects AVX-capable processors
1691 // if the feature has been disabled in firmware. This causes us to crash
1692 // in some of the math functions. For now, we disable those optimizations
1693 // because Microsoft is not going to fix the problem in VS2013.
1694 // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+.
1695 _set_FMA3_enable(0);
1696
1697 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1698 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1699 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1700 ::SetErrorMode(0);
1701
1702#if defined(_DEBUG)
1703 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1704 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1705 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1706 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1707 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1708 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1709#endif
1710
1711 timeBeginPeriod(1);
1712#endif
1713
1714#if PLATFORM(EFL)
1715 ecore_init();
1716#endif
1717
1718 // Need to initialize WTF threading before we start any threads. Cannot initialize JSC
1719 // threading yet, since that would do somethings that we'd like to defer until after we
1720 // have a chance to parse options.
1721 WTF::initializeThreading();
1722
1723 if (char* timeoutString = getenv("JSCTEST_timeout")) {
1724 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
1725 dataLog(
1726 "WARNING: timeout string is malformed, got ", timeoutString,
1727 " but expected a number. Not using a timeout.\n");
1728 } else
1729 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
1730 }
1731
1732#if PLATFORM(IOS)
1733 Options::crashIfCantAllocateJITMemory() = true;
1734#endif
1735
1736 // We can't use destructors in the following code because it uses Windows
1737 // Structured Exception Handling
1738 int res = 0;
1739 TRY
1740 res = jscmain(argc, argv);
1741 EXCEPT(res = 3)
1742 if (Options::logHeapStatisticsAtExit())
1743 HeapStatistics::reportSuccess();
1744
1745#if PLATFORM(EFL)
1746 ecore_shutdown();
1747#endif
1748
1749 jscExit(res);
1750}
1751
1752static void dumpException(GlobalObject* globalObject, JSValue exception)
1753{
1754 printf("Exception: %s\n", exception.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1755 Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
1756 JSValue stackValue = exception.get(globalObject->globalExec(), stackID);
1757 if (!stackValue.isUndefinedOrNull())
1758 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1759}
1760
1761static void dumpException(GlobalObject* globalObject, NakedPtr<Exception> evaluationException)
1762{
1763 if (evaluationException)
1764 dumpException(globalObject, evaluationException->value());
1765}
1766
1767static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump, bool module)
1768{
1769 String fileName;
1770 Vector<char> scriptBuffer;
1771
1772 if (dump)
1773 JSC::Options::dumpGeneratedBytecodes() = true;
1774
1775 VM& vm = globalObject->vm();
1776 bool success = true;
1777
1778 JSFunction* errorHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&](ExecState* exec) {
1779 success = false;
1780 dumpException(globalObject, exec->argument(0));
1781 return JSValue::encode(jsUndefined());
1782 });
1783
1784#if ENABLE(SAMPLING_FLAGS)
1785 SamplingFlags::start();
1786#endif
1787
1788 for (size_t i = 0; i < scripts.size(); i++) {
1789 JSInternalPromise* promise = nullptr;
1790 if (scripts[i].isFile) {
1791 fileName = scripts[i].argument;
1792 if (module)
1793 promise = loadAndEvaluateModule(globalObject->globalExec(), fileName);
1794 else {
1795 if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer))
1796 return false; // fail early so we can catch missing files
1797 }
1798 } else {
1799 size_t commandLineLength = strlen(scripts[i].argument);
1800 scriptBuffer.resize(commandLineLength);
1801 std::copy(scripts[i].argument, scripts[i].argument + commandLineLength, scriptBuffer.begin());
1802 fileName = ASCIILiteral("[Command Line]");
1803 }
1804
1805 vm.startSampling();
1806
1807 if (module) {
1808 if (!promise)
1809 promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
1810 globalObject->globalExec()->clearException();
1811 promise->then(globalObject->globalExec(), nullptr, errorHandler);
1812 globalObject->vm().drainMicrotasks();
1813 } else {
1814 NakedPtr<Exception> evaluationException;
1815 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, fileName), JSValue(), evaluationException);
1816 success = success && !evaluationException;
1817 if (dump && !evaluationException)
1818 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1819 dumpException(globalObject, evaluationException);
1820 }
1821
1822 vm.stopSampling();
1823 globalObject->globalExec()->clearException();
1824 }
1825
1826#if ENABLE(SAMPLING_FLAGS)
1827 SamplingFlags::stop();
1828#endif
1829#if ENABLE(SAMPLING_REGIONS)
1830 SamplingRegion::dump();
1831#endif
1832 vm.dumpSampleData(globalObject->globalExec());
1833#if ENABLE(SAMPLING_COUNTERS)
1834 AbstractSamplingCounter::dump();
1835#endif
1836#if ENABLE(REGEXP_TRACING)
1837 vm.dumpRegExpTrace();
1838#endif
1839 return success;
1840}
1841
1842#define RUNNING_FROM_XCODE 0
1843
1844static void runInteractive(GlobalObject* globalObject)
1845{
1846 String interpreterName(ASCIILiteral("Interpreter"));
1847
1848 bool shouldQuit = false;
1849 while (!shouldQuit) {
1850#if HAVE(READLINE) && !RUNNING_FROM_XCODE
1851 ParserError error;
1852 String source;
1853 do {
1854 error = ParserError();
1855 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
1856 shouldQuit = !line;
1857 if (!line)
1858 break;
1859 source = source + line;
1860 source = source + '\n';
1861 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
1862 if (!line[0])
1863 break;
1864 add_history(line);
1865 } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable);
1866
1867 if (error.isValid()) {
1868 printf("%s:%d\n", error.message().utf8().data(), error.line());
1869 continue;
1870 }
1871
1872
1873 NakedPtr<Exception> evaluationException;
1874 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), evaluationException);
1875#else
1876 printf("%s", interactivePrompt);
1877 Vector<char, 256> line;
1878 int c;
1879 while ((c = getchar()) != EOF) {
1880 // FIXME: Should we also break on \r?
1881 if (c == '\n')
1882 break;
1883 line.append(c);
1884 }
1885 if (line.isEmpty())
1886 break;
1887
1888 NakedPtr<Exception> evaluationException;
1889 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, interpreterName), JSValue(), evaluationException);
1890#endif
1891 if (evaluationException)
1892 printf("Exception: %s\n", evaluationException->value().toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1893 else
1894 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1895
1896 globalObject->globalExec()->clearException();
1897 globalObject->vm().drainMicrotasks();
1898 }
1899 printf("\n");
1900}
1901
1902static NO_RETURN void printUsageStatement(bool help = false)
1903{
1904 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1905 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
1906 fprintf(stderr, " -e Evaluate argument as script code\n");
1907 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
1908 fprintf(stderr, " -h|--help Prints this help message\n");
1909 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
1910 fprintf(stderr, " -m Execute as a module\n");
1911#if HAVE(SIGNAL_H)
1912 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
1913#endif
1914 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
1915 fprintf(stderr, " -x Output exit code before terminating\n");
1916 fprintf(stderr, "\n");
1917 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
1918 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
1919 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
1920 fprintf(stderr, "\n");
1921
1922 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1923}
1924
1925void CommandLine::parseArguments(int argc, char** argv)
1926{
1927 Options::initialize();
1928
1929 int i = 1;
1930 bool needToDumpOptions = false;
1931 bool needToExit = false;
1932
1933 bool hasBadJSCOptions = false;
1934 for (; i < argc; ++i) {
1935 const char* arg = argv[i];
1936 if (!strcmp(arg, "-f")) {
1937 if (++i == argc)
1938 printUsageStatement();
1939 m_scripts.append(Script(true, argv[i]));
1940 continue;
1941 }
1942 if (!strcmp(arg, "-e")) {
1943 if (++i == argc)
1944 printUsageStatement();
1945 m_scripts.append(Script(false, argv[i]));
1946 continue;
1947 }
1948 if (!strcmp(arg, "-i")) {
1949 m_interactive = true;
1950 continue;
1951 }
1952 if (!strcmp(arg, "-d")) {
1953 m_dump = true;
1954 continue;
1955 }
1956 if (!strcmp(arg, "-p")) {
1957 if (++i == argc)
1958 printUsageStatement();
1959 m_profile = true;
1960 m_profilerOutput = argv[i];
1961 continue;
1962 }
1963 if (!strcmp(arg, "-m")) {
1964 m_module = true;
1965 continue;
1966 }
1967 if (!strcmp(arg, "-s")) {
1968#if HAVE(SIGNAL_H)
1969 signal(SIGILL, _exit);
1970 signal(SIGFPE, _exit);
1971 signal(SIGBUS, _exit);
1972 signal(SIGSEGV, _exit);
1973#endif
1974 continue;
1975 }
1976 if (!strcmp(arg, "-x")) {
1977 m_exitCode = true;
1978 continue;
1979 }
1980 if (!strcmp(arg, "--")) {
1981 ++i;
1982 break;
1983 }
1984 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1985 printUsageStatement(true);
1986
1987 if (!strcmp(arg, "--options")) {
1988 needToDumpOptions = true;
1989 needToExit = true;
1990 continue;
1991 }
1992 if (!strcmp(arg, "--dumpOptions")) {
1993 needToDumpOptions = true;
1994 continue;
1995 }
1996
1997 // See if the -- option is a JSC VM option.
1998 if (strstr(arg, "--") == arg) {
1999 if (!JSC::Options::setOption(&arg[2])) {
2000 hasBadJSCOptions = true;
2001 dataLog("ERROR: invalid option: ", arg, "\n");
2002 }
2003 continue;
2004 }
2005
2006 // This arg is not recognized by the VM nor by jsc. Pass it on to the
2007 // script.
2008 m_scripts.append(Script(true, argv[i]));
2009 }
2010
2011 if (hasBadJSCOptions && JSC::Options::validateOptions())
2012 CRASH();
2013
2014 if (m_scripts.isEmpty())
2015 m_interactive = true;
2016
2017 for (; i < argc; ++i)
2018 m_arguments.append(argv[i]);
2019
2020 if (needToDumpOptions)
2021 JSC::Options::dumpAllOptions(stderr, JSC::Options::DumpLevel::Overridden, "All JSC runtime options:");
2022 JSC::Options::ensureOptionsAreCoherent();
2023 if (needToExit)
2024 jscExit(EXIT_SUCCESS);
2025}
2026
2027int jscmain(int argc, char** argv)
2028{
2029 // Note that the options parsing can affect VM creation, and thus
2030 // comes first.
2031 CommandLine options(argc, argv);
2032
2033 // Initialize JSC before getting VM.
2034#if ENABLE(SAMPLING_REGIONS)
2035 WTF::initializeMainThread();
2036#endif
2037 JSC::initializeThreading();
2038
2039 VM* vm = &VM::create(LargeHeap).leakRef();
2040 int result;
2041 {
2042 JSLockHolder locker(vm);
2043
2044 if (options.m_profile && !vm->m_perBytecodeProfiler)
2045 vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
2046
2047 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
2048 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump, options.m_module);
2049 if (options.m_interactive && success)
2050 runInteractive(globalObject);
2051
2052 result = success ? 0 : 3;
2053
2054 if (options.m_exitCode)
2055 printf("jsc exiting %d\n", result);
2056
2057 if (options.m_profile) {
2058 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
2059 fprintf(stderr, "could not save profiler output.\n");
2060 }
2061
2062#if ENABLE(JIT)
2063 if (Options::useExceptionFuzz())
2064 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
2065 bool fireAtEnabled =
2066 Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
2067 if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
2068 printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
2069 if (Options::useOSRExitFuzz()) {
2070 printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks());
2071 printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks());
2072 }
2073#endif
2074 auto compileTimeStats = DFG::Plan::compileTimeStats();
2075 Vector<CString> compileTimeKeys;
2076 for (auto& entry : compileTimeStats)
2077 compileTimeKeys.append(entry.key);
2078 std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
2079 for (CString key : compileTimeKeys)
2080 printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
2081 }
2082
2083 return result;
2084}
2085
2086#if OS(WINDOWS)
2087extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
2088{
2089 return main(argc, const_cast<char**>(argv));
2090}
2091#endif
Note: See TracBrowser for help on using the repository browser.