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

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

[JSC] ArithSqrt should work with any argument type
https://bugs.webkit.org/show_bug.cgi?id=160954

Patch by Benjamin Poulain <[email protected]> on 2016-08-19
Reviewed by Saam Barati.

JSTests:

  • stress/arith-sqrt-on-various-types.js: Added.

(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueAllTypesSqrt):
(testAllTypesCall):
(testSingleTypeCall):
(opaqueSqrtForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueSqrtForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(testException.opaqueSqrtWithException):
(testException):

Source/JavaScriptCore:

Previsouly, ArithSqrt would always OSR Exit if the argument
is not typed Integer, Double, or Boolean.
Since we can't recover by generalizing to those, we continuously
OSR Exit and recompile the same code over and over again.

This patch introduces a fallback to handle the remaining types.

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGMayExit.cpp:

This is somewhat unrelated. While discussing the design of this
with Filip, we decided not to use ToNumber+ArithSqrt despite
the guarantee that ToNumber does not OSR Exit.
Since it does not OSR Exit, we should say so in mayExitImpl().

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArithSqrt):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileArithSqrt):

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