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

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

Add --timeoutMultiplier option to allow some tests more time to run.
https://bugs.webkit.org/show_bug.cgi?id=164951

Reviewed by Yusuke Suzuki.

JSTests:

Extended the timeout for these tests by 50% more because they run quite slow on
low-end machines.

  • stress/op_div-ConstVar.js:
  • stress/op_div-VarConst.js:
  • stress/op_div-VarVar.js:

Source/JavaScriptCore:

  • jsc.cpp:

(timeoutThreadMain):

  • Modified to factor in a timeout multiplier that can adjust the timeout duration.

(startTimeoutThreadIfNeeded):

  • Moved the code that starts the timeout thread here from main() so that we can

call it after command line args have been parsed instead.
(main):

  • Deleted old timeout thread starting code.

(CommandLine::parseArguments):

  • Added parsing of the --timeoutMultiplier option.

(jscmain):

  • Start the timeout thread if needed after we've parsed the command line args.
  • Property svn:eol-style set to native
File size: 117.6 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 "ArrayBuffer.h"
26#include "ArrayPrototype.h"
27#include "BuiltinExecutableCreator.h"
28#include "ButterflyInlines.h"
29#include "CodeBlock.h"
30#include "Completion.h"
31#include "DOMJITGetterSetter.h"
32#include "DOMJITPatchpoint.h"
33#include "DOMJITPatchpointParams.h"
34#include "Disassembler.h"
35#include "Exception.h"
36#include "ExceptionHelpers.h"
37#include "GetterSetter.h"
38#include "HeapProfiler.h"
39#include "HeapSnapshotBuilder.h"
40#include "HeapStatistics.h"
41#include "InitializeThreading.h"
42#include "Interpreter.h"
43#include "JIT.h"
44#include "JSArray.h"
45#include "JSArrayBuffer.h"
46#include "JSCInlines.h"
47#include "JSFunction.h"
48#include "JSInternalPromise.h"
49#include "JSInternalPromiseDeferred.h"
50#include "JSLock.h"
51#include "JSNativeStdFunction.h"
52#include "JSONObject.h"
53#include "JSProxy.h"
54#include "JSString.h"
55#include "JSTypedArrays.h"
56#include "LLIntData.h"
57#include "LLIntThunks.h"
58#include "ObjectConstructor.h"
59#include "ParserError.h"
60#include "ProfilerDatabase.h"
61#include "ProtoCallFrame.h"
62#include "SamplingProfiler.h"
63#include "ShadowChicken.h"
64#include "StackVisitor.h"
65#include "StructureInlines.h"
66#include "StructureRareDataInlines.h"
67#include "SuperSampler.h"
68#include "TestRunnerUtils.h"
69#include "TypeProfilerLog.h"
70#include "WasmPlan.h"
71#include <locale.h>
72#include <math.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <thread>
77#include <type_traits>
78#include <wtf/CurrentTime.h>
79#include <wtf/MainThread.h>
80#include <wtf/NeverDestroyed.h>
81#include <wtf/StringPrintStream.h>
82#include <wtf/text/StringBuilder.h>
83
84#if OS(WINDOWS)
85#include <direct.h>
86#else
87#include <unistd.h>
88#endif
89
90#if HAVE(READLINE)
91// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
92// We #define it to something else to avoid this conflict.
93#define Function ReadlineFunction
94#include <readline/history.h>
95#include <readline/readline.h>
96#undef Function
97#endif
98
99#if HAVE(SYS_TIME_H)
100#include <sys/time.h>
101#endif
102
103#if HAVE(SIGNAL_H)
104#include <signal.h>
105#endif
106
107#if COMPILER(MSVC)
108#include <crtdbg.h>
109#include <mmsystem.h>
110#include <windows.h>
111#endif
112
113#if PLATFORM(IOS) && CPU(ARM_THUMB2)
114#include <fenv.h>
115#include <arm/arch.h>
116#endif
117
118#if PLATFORM(EFL)
119#include <Ecore.h>
120#endif
121
122#if !defined(PATH_MAX)
123#define PATH_MAX 4096
124#endif
125
126using namespace JSC;
127using namespace WTF;
128
129namespace {
130
131NO_RETURN_WITH_VALUE static void jscExit(int status)
132{
133 waitForAsynchronousDisassembly();
134
135#if ENABLE(DFG_JIT)
136 if (DFG::isCrashing()) {
137 for (;;) {
138#if OS(WINDOWS)
139 Sleep(1000);
140#else
141 pause();
142#endif
143 }
144 }
145#endif // ENABLE(DFG_JIT)
146 exit(status);
147}
148
149class Element;
150class ElementHandleOwner;
151class Masuqerader;
152class Root;
153class RuntimeArray;
154
155class Element : public JSNonFinalObject {
156public:
157 Element(VM& vm, Structure* structure)
158 : Base(vm, structure)
159 {
160 }
161
162 typedef JSNonFinalObject Base;
163 static const bool needsDestruction = false;
164
165 Root* root() const { return m_root.get(); }
166 void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); }
167
168 static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
169 {
170 Structure* structure = createStructure(vm, globalObject, jsNull());
171 Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure);
172 element->finishCreation(vm, root);
173 return element;
174 }
175
176 void finishCreation(VM&, Root*);
177
178 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
179 {
180 Element* thisObject = jsCast<Element*>(cell);
181 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
182 Base::visitChildren(thisObject, visitor);
183 visitor.append(&thisObject->m_root);
184 }
185
186 static ElementHandleOwner* handleOwner();
187
188 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
189 {
190 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
191 }
192
193 DECLARE_INFO;
194
195private:
196 WriteBarrier<Root> m_root;
197};
198
199class ElementHandleOwner : public WeakHandleOwner {
200public:
201 virtual bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
202 {
203 Element* element = jsCast<Element*>(handle.slot()->asCell());
204 return visitor.containsOpaqueRoot(element->root());
205 }
206};
207
208class Masquerader : public JSNonFinalObject {
209public:
210 Masquerader(VM& vm, Structure* structure)
211 : Base(vm, structure)
212 {
213 }
214
215 typedef JSNonFinalObject Base;
216 static const unsigned StructureFlags = Base::StructureFlags | JSC::MasqueradesAsUndefined;
217
218 static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
219 {
220 globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(vm, "Masquerading object allocated");
221 Structure* structure = createStructure(vm, globalObject, jsNull());
222 Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
223 result->finishCreation(vm);
224 return result;
225 }
226
227 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
228 {
229 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
230 }
231
232 DECLARE_INFO;
233};
234
235class Root : public JSDestructibleObject {
236public:
237 Root(VM& vm, Structure* structure)
238 : Base(vm, structure)
239 {
240 }
241
242 Element* element()
243 {
244 return m_element.get();
245 }
246
247 void setElement(Element* element)
248 {
249 Weak<Element> newElement(element, Element::handleOwner());
250 m_element.swap(newElement);
251 }
252
253 static Root* create(VM& vm, JSGlobalObject* globalObject)
254 {
255 Structure* structure = createStructure(vm, globalObject, jsNull());
256 Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
257 root->finishCreation(vm);
258 return root;
259 }
260
261 typedef JSDestructibleObject Base;
262
263 DECLARE_INFO;
264 static const bool needsDestruction = true;
265
266 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
267 {
268 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
269 }
270
271 static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
272 {
273 Base::visitChildren(thisObject, visitor);
274 visitor.addOpaqueRoot(thisObject);
275 }
276
277private:
278 Weak<Element> m_element;
279};
280
281class ImpureGetter : public JSNonFinalObject {
282public:
283 ImpureGetter(VM& vm, Structure* structure)
284 : Base(vm, structure)
285 {
286 }
287
288 DECLARE_INFO;
289 typedef JSNonFinalObject Base;
290 static const unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::OverridesGetOwnPropertySlot;
291
292 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
293 {
294 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
295 }
296
297 static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
298 {
299 ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
300 getter->finishCreation(vm, delegate);
301 return getter;
302 }
303
304 void finishCreation(VM& vm, JSObject* delegate)
305 {
306 Base::finishCreation(vm);
307 if (delegate)
308 m_delegate.set(vm, this, delegate);
309 }
310
311 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
312 {
313 VM& vm = exec->vm();
314 auto scope = DECLARE_THROW_SCOPE(vm);
315 ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
316
317 if (thisObject->m_delegate) {
318 if (thisObject->m_delegate->getPropertySlot(exec, name, slot))
319 return true;
320 RETURN_IF_EXCEPTION(scope, false);
321 }
322
323 return Base::getOwnPropertySlot(object, exec, name, slot);
324 }
325
326 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
327 {
328 Base::visitChildren(cell, visitor);
329 ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell);
330 visitor.append(&thisObject->m_delegate);
331 }
332
333 void setDelegate(VM& vm, JSObject* delegate)
334 {
335 m_delegate.set(vm, this, delegate);
336 }
337
338private:
339 WriteBarrier<JSObject> m_delegate;
340};
341
342class CustomGetter : public JSNonFinalObject {
343public:
344 CustomGetter(VM& vm, Structure* structure)
345 : Base(vm, structure)
346 {
347 }
348
349 DECLARE_INFO;
350 typedef JSNonFinalObject Base;
351 static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot;
352
353 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
354 {
355 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
356 }
357
358 static CustomGetter* create(VM& vm, Structure* structure)
359 {
360 CustomGetter* getter = new (NotNull, allocateCell<CustomGetter>(vm.heap, sizeof(CustomGetter))) CustomGetter(vm, structure);
361 getter->finishCreation(vm);
362 return getter;
363 }
364
365 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
366 {
367 CustomGetter* thisObject = jsCast<CustomGetter*>(object);
368 if (propertyName == PropertyName(Identifier::fromString(exec, "customGetter"))) {
369 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->customGetter);
370 return true;
371 }
372 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
373 }
374
375private:
376 static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
377 {
378 VM& vm = exec->vm();
379 auto scope = DECLARE_THROW_SCOPE(vm);
380
381 CustomGetter* thisObject = jsDynamicCast<CustomGetter*>(JSValue::decode(thisValue));
382 if (!thisObject)
383 return throwVMTypeError(exec, scope);
384 bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow"))).toBoolean(exec);
385 if (shouldThrow)
386 return throwVMTypeError(exec, scope);
387 return JSValue::encode(jsNumber(100));
388 }
389};
390
391class RuntimeArray : public JSArray {
392public:
393 typedef JSArray Base;
394 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
395
396 static RuntimeArray* create(ExecState* exec)
397 {
398 VM& vm = exec->vm();
399 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
400 Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
401 RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
402 runtimeArray->finishCreation(exec);
403 vm.heap.addFinalizer(runtimeArray, destroy);
404 return runtimeArray;
405 }
406
407 ~RuntimeArray() { }
408
409 static void destroy(JSCell* cell)
410 {
411 static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
412 }
413
414 static const bool needsDestruction = false;
415
416 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
417 {
418 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
419 if (propertyName == exec->propertyNames().length) {
420 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
421 return true;
422 }
423
424 Optional<uint32_t> index = parseIndex(propertyName);
425 if (index && index.value() < thisObject->getLength()) {
426 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
427 return true;
428 }
429
430 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
431 }
432
433 static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
434 {
435 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
436 if (index < thisObject->getLength()) {
437 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
438 return true;
439 }
440
441 return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
442 }
443
444 static NO_RETURN_DUE_TO_CRASH bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
445 {
446 RELEASE_ASSERT_NOT_REACHED();
447 }
448
449 static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
450 {
451 RELEASE_ASSERT_NOT_REACHED();
452 }
453
454 unsigned getLength() const { return m_vector.size(); }
455
456 DECLARE_INFO;
457
458 static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
459 {
460 return globalObject->arrayPrototype();
461 }
462
463 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
464 {
465 return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass);
466 }
467
468protected:
469 void finishCreation(ExecState* exec)
470 {
471 Base::finishCreation(exec->vm());
472 ASSERT(inherits(info()));
473
474 for (size_t i = 0; i < exec->argumentCount(); i++)
475 m_vector.append(exec->argument(i).toInt32(exec));
476 }
477
478private:
479 RuntimeArray(ExecState* exec, Structure* structure)
480 : JSArray(exec->vm(), structure, 0)
481 {
482 }
483
484 static EncodedJSValue lengthGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
485 {
486 VM& vm = exec->vm();
487 auto scope = DECLARE_THROW_SCOPE(vm);
488
489 RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
490 if (!thisObject)
491 return throwVMTypeError(exec, scope);
492 return JSValue::encode(jsNumber(thisObject->getLength()));
493 }
494
495 Vector<int> m_vector;
496};
497
498class SimpleObject : public JSNonFinalObject {
499public:
500 SimpleObject(VM& vm, Structure* structure)
501 : Base(vm, structure)
502 {
503 }
504
505 typedef JSNonFinalObject Base;
506 static const bool needsDestruction = false;
507
508 static SimpleObject* create(VM& vm, JSGlobalObject* globalObject)
509 {
510 Structure* structure = createStructure(vm, globalObject, jsNull());
511 SimpleObject* simpleObject = new (NotNull, allocateCell<SimpleObject>(vm.heap, sizeof(SimpleObject))) SimpleObject(vm, structure);
512 simpleObject->finishCreation(vm);
513 return simpleObject;
514 }
515
516 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
517 {
518 SimpleObject* thisObject = jsCast<SimpleObject*>(cell);
519 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
520 Base::visitChildren(thisObject, visitor);
521 visitor.append(&thisObject->m_hiddenValue);
522 }
523
524 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
525 {
526 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
527 }
528
529 JSValue hiddenValue()
530 {
531 return m_hiddenValue.get();
532 }
533
534 void setHiddenValue(VM& vm, JSValue value)
535 {
536 ASSERT(value.isCell());
537 m_hiddenValue.set(vm, this, value);
538 }
539
540 DECLARE_INFO;
541
542private:
543 WriteBarrier<JSC::Unknown> m_hiddenValue;
544};
545
546class DOMJITNode : public JSNonFinalObject {
547public:
548 DOMJITNode(VM& vm, Structure* structure)
549 : Base(vm, structure)
550 {
551 }
552
553 DECLARE_INFO;
554 typedef JSNonFinalObject Base;
555 static const unsigned StructureFlags = Base::StructureFlags;
556
557 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
558 {
559 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
560 }
561
562#if ENABLE(JIT)
563 static Ref<DOMJIT::Patchpoint> checkDOMJITNode()
564 {
565 Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
566 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
567 CCallHelpers::JumpList failureCases;
568 failureCases.append(jit.branch8(
569 CCallHelpers::NotEqual,
570 CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
571 CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
572 return failureCases;
573 });
574 return patchpoint;
575 }
576#endif
577
578 static DOMJITNode* create(VM& vm, Structure* structure)
579 {
580 DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure);
581 getter->finishCreation(vm);
582 return getter;
583 }
584
585 int32_t value() const
586 {
587 return m_value;
588 }
589
590 static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(DOMJITNode, m_value); }
591
592private:
593 int32_t m_value { 42 };
594};
595
596class DOMJITGetter : public DOMJITNode {
597public:
598 DOMJITGetter(VM& vm, Structure* structure)
599 : Base(vm, structure)
600 {
601 }
602
603 DECLARE_INFO;
604 typedef DOMJITNode Base;
605 static const unsigned StructureFlags = Base::StructureFlags;
606
607 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
608 {
609 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
610 }
611
612 static DOMJITGetter* create(VM& vm, Structure* structure)
613 {
614 DOMJITGetter* getter = new (NotNull, allocateCell<DOMJITGetter>(vm.heap, sizeof(DOMJITGetter))) DOMJITGetter(vm, structure);
615 getter->finishCreation(vm);
616 return getter;
617 }
618
619 class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
620 public:
621 DOMJITNodeDOMJIT()
622 : DOMJIT::GetterSetter(DOMJITGetter::customGetter, nullptr, DOMJITNode::info(), SpecInt32Only)
623 {
624 }
625
626#if ENABLE(JIT)
627 Ref<DOMJIT::Patchpoint> checkDOM() override
628 {
629 return DOMJITNode::checkDOMJITNode();
630 }
631
632 static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer)
633 {
634 NativeCallFrameTracer tracer(&exec->vm(), exec);
635 return JSValue::encode(jsNumber(static_cast<DOMJITGetter*>(pointer)->value()));
636 }
637
638 Ref<DOMJIT::CallDOMGetterPatchpoint> callDOMGetter() override
639 {
640 Ref<DOMJIT::CallDOMGetterPatchpoint> patchpoint = DOMJIT::CallDOMGetterPatchpoint::create();
641 patchpoint->requireGlobalObject = false;
642 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
643 JSValueRegs results = params[0].jsValueRegs();
644 GPRReg dom = params[1].gpr();
645 params.addSlowPathCall(jit.jump(), jit, slowCall, results, dom);
646 return CCallHelpers::JumpList();
647
648 });
649 return patchpoint;
650 }
651#endif
652 };
653
654 static DOMJIT::GetterSetter* domJITNodeGetterSetter()
655 {
656 static NeverDestroyed<DOMJITNodeDOMJIT> graph;
657 return &graph.get();
658 }
659
660private:
661 void finishCreation(VM& vm)
662 {
663 Base::finishCreation(vm);
664 DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
665 CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
666 putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
667 }
668
669 static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
670 {
671 VM& vm = exec->vm();
672 auto scope = DECLARE_THROW_SCOPE(vm);
673
674 DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(JSValue::decode(thisValue));
675 if (!thisObject)
676 return throwVMTypeError(exec, scope);
677 return JSValue::encode(jsNumber(thisObject->value()));
678 }
679};
680
681class DOMJITGetterComplex : public DOMJITNode {
682public:
683 DOMJITGetterComplex(VM& vm, Structure* structure)
684 : Base(vm, structure)
685 {
686 }
687
688 DECLARE_INFO;
689 typedef DOMJITNode Base;
690 static const unsigned StructureFlags = Base::StructureFlags;
691
692 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
693 {
694 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
695 }
696
697 static DOMJITGetterComplex* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
698 {
699 DOMJITGetterComplex* getter = new (NotNull, allocateCell<DOMJITGetterComplex>(vm.heap, sizeof(DOMJITGetterComplex))) DOMJITGetterComplex(vm, structure);
700 getter->finishCreation(vm, globalObject);
701 return getter;
702 }
703
704 class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
705 public:
706 DOMJITNodeDOMJIT()
707 : DOMJIT::GetterSetter(DOMJITGetterComplex::customGetter, nullptr, DOMJITNode::info(), SpecInt32Only)
708 {
709 }
710
711#if ENABLE(JIT)
712 Ref<DOMJIT::Patchpoint> checkDOM() override
713 {
714 return DOMJITNode::checkDOMJITNode();
715 }
716
717 static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer)
718 {
719 VM& vm = exec->vm();
720 NativeCallFrameTracer tracer(&vm, exec);
721 auto scope = DECLARE_THROW_SCOPE(vm);
722 auto* object = static_cast<DOMJITNode*>(pointer);
723 auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(object);
724 if (domjitGetterComplex) {
725 if (domjitGetterComplex->m_enableException)
726 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
727 }
728 return JSValue::encode(jsNumber(object->value()));
729 }
730
731 Ref<DOMJIT::CallDOMGetterPatchpoint> callDOMGetter() override
732 {
733 RefPtr<DOMJIT::CallDOMGetterPatchpoint> patchpoint = DOMJIT::CallDOMGetterPatchpoint::create();
734 static_assert(GPRInfo::numberOfRegisters >= 4, "Number of registers should be larger or equal to 4.");
735 patchpoint->numGPScratchRegisters = GPRInfo::numberOfRegisters - 4;
736 patchpoint->numFPScratchRegisters = 3;
737 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
738 JSValueRegs results = params[0].jsValueRegs();
739 GPRReg domGPR = params[1].gpr();
740 for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i)
741 jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i));
742
743 params.addSlowPathCall(jit.jump(), jit, slowCall, results, domGPR);
744 return CCallHelpers::JumpList();
745
746 });
747 return *patchpoint.get();
748 }
749#endif
750 };
751
752 static DOMJIT::GetterSetter* domJITNodeGetterSetter()
753 {
754 static NeverDestroyed<DOMJITNodeDOMJIT> graph;
755 return &graph.get();
756 }
757
758private:
759 void finishCreation(VM& vm, JSGlobalObject* globalObject)
760 {
761 Base::finishCreation(vm);
762 DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
763 CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
764 putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
765 putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "enableException"), 0, functionEnableException, NoIntrinsic, 0);
766 }
767
768 static EncodedJSValue JSC_HOST_CALL functionEnableException(ExecState* exec)
769 {
770 auto* object = jsDynamicCast<DOMJITGetterComplex*>(exec->thisValue());
771 if (object)
772 object->m_enableException = true;
773 return JSValue::encode(jsUndefined());
774 }
775
776 static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
777 {
778 VM& vm = exec->vm();
779 auto scope = DECLARE_THROW_SCOPE(vm);
780
781 auto* thisObject = jsDynamicCast<DOMJITNode*>(JSValue::decode(thisValue));
782 if (!thisObject)
783 return throwVMTypeError(exec, scope);
784 if (auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(JSValue::decode(thisValue))) {
785 if (domjitGetterComplex->m_enableException)
786 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
787 }
788 return JSValue::encode(jsNumber(thisObject->value()));
789 }
790
791 bool m_enableException { false };
792};
793
794class DOMJITFunctionObject : public DOMJITNode {
795public:
796 DOMJITFunctionObject(VM& vm, Structure* structure)
797 : Base(vm, structure)
798 {
799 }
800
801 DECLARE_INFO;
802 typedef DOMJITNode Base;
803 static const unsigned StructureFlags = Base::StructureFlags;
804
805
806 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
807 {
808 return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
809 }
810
811 static DOMJITFunctionObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
812 {
813 DOMJITFunctionObject* object = new (NotNull, allocateCell<DOMJITFunctionObject>(vm.heap, sizeof(DOMJITFunctionObject))) DOMJITFunctionObject(vm, structure);
814 object->finishCreation(vm, globalObject);
815 return object;
816 }
817
818 static EncodedJSValue JSC_HOST_CALL safeFunction(ExecState* exec)
819 {
820 VM& vm = exec->vm();
821 auto scope = DECLARE_THROW_SCOPE(vm);
822
823 DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(exec->thisValue());
824 if (!thisObject)
825 return throwVMTypeError(exec, scope);
826 return JSValue::encode(jsNumber(thisObject->value()));
827 }
828
829#if ENABLE(JIT)
830 static EncodedJSValue JIT_OPERATION unsafeFunction(ExecState* exec, DOMJITNode* node)
831 {
832 NativeCallFrameTracer tracer(&exec->vm(), exec);
833 return JSValue::encode(jsNumber(node->value()));
834 }
835
836 static Ref<DOMJIT::Patchpoint> checkDOMJITNode()
837 {
838 static const double value = 42.0;
839 Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
840 patchpoint->numFPScratchRegisters = 1;
841 patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
842 CCallHelpers::JumpList failureCases;
843 // May use scratch registers.
844 jit.loadDouble(CCallHelpers::TrustedImmPtr(&value), params.fpScratch(0));
845 failureCases.append(jit.branch8(
846 CCallHelpers::NotEqual,
847 CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
848 CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
849 return failureCases;
850 });
851 return patchpoint;
852 }
853#endif
854
855private:
856 void finishCreation(VM&, JSGlobalObject*);
857};
858
859#if ENABLE(JIT)
860static const DOMJIT::Signature DOMJITFunctionObjectSignature((uintptr_t)DOMJITFunctionObject::unsafeFunction, DOMJITFunctionObject::checkDOMJITNode, DOMJITFunctionObject::info(), DOMJIT::Effect::forRead(DOMJIT::HeapRange::top()), SpecInt32Only);
861#endif
862
863void DOMJITFunctionObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
864{
865 Base::finishCreation(vm);
866#if ENABLE(JIT)
867 putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "func"), 0, safeFunction, NoIntrinsic, &DOMJITFunctionObjectSignature, ReadOnly);
868#else
869 putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "func"), 0, safeFunction, NoIntrinsic, nullptr, ReadOnly);
870#endif
871}
872
873
874const ClassInfo Element::s_info = { "Element", &Base::s_info, nullptr, CREATE_METHOD_TABLE(Element) };
875const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, nullptr, CREATE_METHOD_TABLE(Masquerader) };
876const ClassInfo Root::s_info = { "Root", &Base::s_info, nullptr, CREATE_METHOD_TABLE(Root) };
877const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, nullptr, CREATE_METHOD_TABLE(ImpureGetter) };
878const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, nullptr, CREATE_METHOD_TABLE(CustomGetter) };
879const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITNode) };
880const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITGetter) };
881const ClassInfo DOMJITGetterComplex::s_info = { "DOMJITGetterComplex", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITGetterComplex) };
882const ClassInfo DOMJITFunctionObject::s_info = { "DOMJITFunctionObject", &Base::s_info, nullptr, CREATE_METHOD_TABLE(DOMJITFunctionObject) };
883const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RuntimeArray) };
884const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, nullptr, CREATE_METHOD_TABLE(SimpleObject) };
885static bool test262AsyncPassed { false };
886static bool test262AsyncTest { false };
887
888ElementHandleOwner* Element::handleOwner()
889{
890 static ElementHandleOwner* owner = 0;
891 if (!owner)
892 owner = new ElementHandleOwner();
893 return owner;
894}
895
896void Element::finishCreation(VM& vm, Root* root)
897{
898 Base::finishCreation(vm);
899 setRoot(vm, root);
900 m_root->setElement(this);
901}
902
903}
904
905static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
906
907static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
908static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
909static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
910static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
911static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
912static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
913static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState*);
914static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState*);
915static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
916static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
917static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
918
919static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
920static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
921static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
922static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
923static EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState*);
924static EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState*);
925static EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState*);
926static EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState*);
927static EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState*);
928static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
929static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
930static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
931static EncodedJSValue JSC_HOST_CALL functionSleepSeconds(ExecState*);
932static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
933static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
934static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
935static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
936static EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*);
937static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*);
938static EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState*);
939static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState*);
940#ifndef NDEBUG
941static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
942#endif
943static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
944static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
945static EncodedJSValue JSC_HOST_CALL functionRunString(ExecState*);
946static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
947static EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState*);
948static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
949static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
950static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
951static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
952static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
953static EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState*);
954static EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState*);
955static EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState*);
956static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
957static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
958static EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState*);
959static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
960static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
961static EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState*);
962static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
963static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*);
964static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
965static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
966static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
967static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
968static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
969static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
970static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
971static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
972static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
973static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
974static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
975static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
976static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
977static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
978static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*);
979static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*);
980static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*);
981static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*);
982static EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState*);
983static EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState*);
984static EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*);
985static EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState*);
986static EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*);
987static EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState*);
988#if ENABLE(SAMPLING_PROFILER)
989static EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState*);
990static EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState*);
991#endif
992
993#if ENABLE(WEBASSEMBLY)
994static EncodedJSValue JSC_HOST_CALL functionTestWasmModuleFunctions(ExecState*);
995#endif
996
997#if ENABLE(SAMPLING_FLAGS)
998static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
999static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
1000#endif
1001
1002static EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState*);
1003static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState*);
1004static EncodedJSValue JSC_HOST_CALL functionGetRandomSeed(ExecState*);
1005static EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState*);
1006static EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState*);
1007
1008struct Script {
1009 enum class StrictMode {
1010 Strict,
1011 Sloppy
1012 };
1013
1014 enum class ScriptType {
1015 Script,
1016 Module
1017 };
1018
1019 enum class CodeSource {
1020 File,
1021 CommandLine
1022 };
1023
1024 StrictMode strictMode;
1025 CodeSource codeSource;
1026 ScriptType scriptType;
1027 char* argument;
1028
1029 Script(StrictMode strictMode, CodeSource codeSource, ScriptType scriptType, char *argument)
1030 : strictMode(strictMode)
1031 , codeSource(codeSource)
1032 , scriptType(scriptType)
1033 , argument(argument)
1034 {
1035 if (strictMode == StrictMode::Strict)
1036 ASSERT(codeSource == CodeSource::File);
1037 }
1038};
1039
1040class CommandLine {
1041public:
1042 CommandLine(int argc, char** argv)
1043 {
1044 parseArguments(argc, argv);
1045 }
1046
1047 bool m_interactive { false };
1048 bool m_dump { false };
1049 bool m_module { false };
1050 bool m_exitCode { false };
1051 Vector<Script> m_scripts;
1052 Vector<String> m_arguments;
1053 bool m_profile { false };
1054 String m_profilerOutput;
1055 String m_uncaughtExceptionName;
1056 bool m_alwaysDumpUncaughtException { false };
1057 bool m_dumpSamplingProfilerData { false };
1058 bool m_enableRemoteDebugging { false };
1059
1060 void parseArguments(int, char**);
1061};
1062
1063static const char interactivePrompt[] = ">>> ";
1064
1065class StopWatch {
1066public:
1067 void start();
1068 void stop();
1069 long getElapsedMS(); // call stop() first
1070
1071private:
1072 double m_startTime;
1073 double m_stopTime;
1074};
1075
1076void StopWatch::start()
1077{
1078 m_startTime = monotonicallyIncreasingTime();
1079}
1080
1081void StopWatch::stop()
1082{
1083 m_stopTime = monotonicallyIncreasingTime();
1084}
1085
1086long StopWatch::getElapsedMS()
1087{
1088 return static_cast<long>((m_stopTime - m_startTime) * 1000);
1089}
1090
1091template<typename Vector>
1092static inline String stringFromUTF(const Vector& utf8)
1093{
1094 return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size());
1095}
1096
1097template<typename Vector>
1098static inline SourceCode jscSource(const Vector& utf8, const String& filename)
1099{
1100 String str = stringFromUTF(utf8);
1101 return makeSource(str, filename);
1102}
1103
1104class GlobalObject : public JSGlobalObject {
1105private:
1106 GlobalObject(VM&, Structure*);
1107
1108public:
1109 typedef JSGlobalObject Base;
1110
1111 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
1112 {
1113 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
1114 object->finishCreation(vm, arguments);
1115 vm.heap.addFinalizer(object, destroy);
1116 return object;
1117 }
1118
1119 static const bool needsDestruction = false;
1120
1121 DECLARE_INFO;
1122 static const GlobalObjectMethodTable s_globalObjectMethodTable;
1123
1124 static Structure* createStructure(VM& vm, JSValue prototype)
1125 {
1126 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
1127 }
1128
1129 static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags::createAllEnabled(); }
1130
1131protected:
1132 void finishCreation(VM& vm, const Vector<String>& arguments)
1133 {
1134 Base::finishCreation(vm);
1135
1136 addFunction(vm, "debug", functionDebug, 1);
1137 addFunction(vm, "describe", functionDescribe, 1);
1138 addFunction(vm, "describeArray", functionDescribeArray, 1);
1139 addFunction(vm, "print", functionPrintStdOut, 1);
1140 addFunction(vm, "printErr", functionPrintStdErr, 1);
1141 addFunction(vm, "quit", functionQuit, 0);
1142 addFunction(vm, "abort", functionAbort, 0);
1143 addFunction(vm, "gc", functionGCAndSweep, 0);
1144 addFunction(vm, "fullGC", functionFullGC, 0);
1145 addFunction(vm, "edenGC", functionEdenGC, 0);
1146 addFunction(vm, "forceGCSlowPaths", functionForceGCSlowPaths, 0);
1147 addFunction(vm, "gcHeapSize", functionHeapSize, 0);
1148 addFunction(vm, "addressOf", functionAddressOf, 1);
1149 addFunction(vm, "getGetterSetter", functionGetGetterSetter, 2);
1150#ifndef NDEBUG
1151 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
1152#endif
1153 addFunction(vm, "version", functionVersion, 1);
1154 addFunction(vm, "run", functionRun, 1);
1155 addFunction(vm, "runString", functionRunString, 1);
1156 addFunction(vm, "load", functionLoad, 1);
1157 addFunction(vm, "loadString", functionLoadString, 1);
1158 addFunction(vm, "readFile", functionReadFile, 2);
1159 addFunction(vm, "read", functionReadFile, 2);
1160 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
1161 addFunction(vm, "sleepSeconds", functionSleepSeconds, 1);
1162 addFunction(vm, "jscStack", functionJSCStack, 1);
1163 addFunction(vm, "readline", functionReadline, 0);
1164 addFunction(vm, "preciseTime", functionPreciseTime, 0);
1165 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
1166 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
1167 addFunction(vm, "noDFG", functionNoDFG, 1);
1168 addFunction(vm, "noFTL", functionNoFTL, 1);
1169 addFunction(vm, "noOSRExitFuzzing", functionNoOSRExitFuzzing, 1);
1170 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
1171 addFunction(vm, "jscOptions", functionJSCOptions, 0);
1172 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
1173 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
1174 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
1175 addFunction(vm, "failNextNewCodeBlock", functionFailNextNewCodeBlock, 1);
1176#if ENABLE(SAMPLING_FLAGS)
1177 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
1178 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
1179#endif
1180 addFunction(vm, "shadowChickenFunctionsOnStack", functionShadowChickenFunctionsOnStack, 0);
1181 addFunction(vm, "setGlobalConstRedeclarationShouldNotThrow", functionSetGlobalConstRedeclarationShouldNotThrow, 0);
1182 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
1183 addConstructableFunction(vm, "Element", functionCreateElement, 1);
1184 addFunction(vm, "getElement", functionGetElement, 1);
1185 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
1186
1187 addConstructableFunction(vm, "SimpleObject", functionCreateSimpleObject, 0);
1188 addFunction(vm, "getHiddenValue", functionGetHiddenValue, 1);
1189 addFunction(vm, "setHiddenValue", functionSetHiddenValue, 2);
1190
1191 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum);
1192 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum);
1193 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum);
1194 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum);
1195 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, DontEnum);
1196 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum);
1197
1198 addFunction(vm, "effectful42", functionEffectful42, 0);
1199 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
1200 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
1201
1202 addFunction(vm, "createProxy", functionCreateProxy, 1);
1203 addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
1204
1205 addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
1206 addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
1207 addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0);
1208 addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0);
1209 addFunction(vm, "createDOMJITGetterComplexObject", functionCreateDOMJITGetterComplexObject, 0);
1210 addFunction(vm, "createDOMJITFunctionObject", functionCreateDOMJITFunctionObject, 0);
1211 addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
1212 addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
1213 addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
1214
1215 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
1216 addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
1217 addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
1218
1219 addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
1220 addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
1221 addFunction(vm, "basicBlockExecutionCount", functionBasicBlockExecutionCount, 2);
1222
1223 addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
1224
1225 addFunction(vm, "drainMicrotasks", functionDrainMicrotasks, 0);
1226
1227 addFunction(vm, "getRandomSeed", functionGetRandomSeed, 0);
1228 addFunction(vm, "setRandomSeed", functionSetRandomSeed, 1);
1229 addFunction(vm, "isRope", functionIsRope, 1);
1230
1231 addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
1232
1233 addFunction(vm, "loadModule", functionLoadModule, 1);
1234 addFunction(vm, "checkModuleSyntax", functionCheckModuleSyntax, 1);
1235
1236 addFunction(vm, "platformSupportsSamplingProfiler", functionPlatformSupportsSamplingProfiler, 0);
1237 addFunction(vm, "generateHeapSnapshot", functionGenerateHeapSnapshot, 0);
1238 addFunction(vm, "resetSuperSamplerState", functionResetSuperSamplerState, 0);
1239 addFunction(vm, "ensureArrayStorage", functionEnsureArrayStorage, 0);
1240#if ENABLE(SAMPLING_PROFILER)
1241 addFunction(vm, "startSamplingProfiler", functionStartSamplingProfiler, 0);
1242 addFunction(vm, "samplingProfilerStackTraces", functionSamplingProfilerStackTraces, 0);
1243#endif
1244
1245#if ENABLE(WEBASSEMBLY)
1246 addFunction(vm, "testWasmModuleFunctions", functionTestWasmModuleFunctions, 0);
1247#endif
1248
1249 if (!arguments.isEmpty()) {
1250 JSArray* array = constructEmptyArray(globalExec(), 0);
1251 for (size_t i = 0; i < arguments.size(); ++i)
1252 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
1253 putDirect(vm, Identifier::fromString(globalExec(), "arguments"), array);
1254 }
1255
1256 putDirect(vm, Identifier::fromString(globalExec(), "console"), jsUndefined());
1257 }
1258
1259 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
1260 {
1261 Identifier identifier = Identifier::fromString(&vm, name);
1262 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
1263 }
1264
1265 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
1266 {
1267 Identifier identifier = Identifier::fromString(&vm, name);
1268 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
1269 }
1270
1271 static JSInternalPromise* moduleLoaderResolve(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
1272 static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue);
1273};
1274
1275const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, nullptr, CREATE_METHOD_TABLE(GlobalObject) };
1276const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, nullptr, nullptr };
1277
1278
1279GlobalObject::GlobalObject(VM& vm, Structure* structure)
1280 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
1281{
1282}
1283
1284static UChar pathSeparator()
1285{
1286#if OS(WINDOWS)
1287 return '\\';
1288#else
1289 return '/';
1290#endif
1291}
1292
1293struct DirectoryName {
1294 // In unix, it is "/". In Windows, it becomes a drive letter like "C:\"
1295 String rootName;
1296
1297 // If the directory name is "/home/WebKit", this becomes "home/WebKit". If the directory name is "/", this becomes "".
1298 String queryName;
1299};
1300
1301struct ModuleName {
1302 ModuleName(const String& moduleName);
1303
1304 bool startsWithRoot() const
1305 {
1306 return !queries.isEmpty() && queries[0].isEmpty();
1307 }
1308
1309 Vector<String> queries;
1310};
1311
1312ModuleName::ModuleName(const String& moduleName)
1313{
1314 // A module name given from code is represented as the UNIX style path. Like, `./A/B.js`.
1315 moduleName.split('/', true, queries);
1316}
1317
1318static bool extractDirectoryName(const String& absolutePathToFile, DirectoryName& directoryName)
1319{
1320 size_t firstSeparatorPosition = absolutePathToFile.find(pathSeparator());
1321 if (firstSeparatorPosition == notFound)
1322 return false;
1323 directoryName.rootName = absolutePathToFile.substring(0, firstSeparatorPosition + 1); // Include the separator.
1324 size_t lastSeparatorPosition = absolutePathToFile.reverseFind(pathSeparator());
1325 ASSERT_WITH_MESSAGE(lastSeparatorPosition != notFound, "If the separator is not found, this function already returns when performing the forward search.");
1326 if (firstSeparatorPosition == lastSeparatorPosition)
1327 directoryName.queryName = StringImpl::empty();
1328 else {
1329 size_t queryStartPosition = firstSeparatorPosition + 1;
1330 size_t queryLength = lastSeparatorPosition - queryStartPosition; // Not include the last separator.
1331 directoryName.queryName = absolutePathToFile.substring(queryStartPosition, queryLength);
1332 }
1333 return true;
1334}
1335
1336static bool currentWorkingDirectory(DirectoryName& directoryName)
1337{
1338#if OS(WINDOWS)
1339 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364934.aspx
1340 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
1341 // The _MAX_PATH in Windows is 260. If the path of the current working directory is longer than that, _getcwd truncates the result.
1342 // And other I/O functions taking a path name also truncate it. To avoid this situation,
1343 //
1344 // (1). When opening the file in Windows for modules, we always use the abosolute path and add "\\?\" prefix to the path name.
1345 // (2). When retrieving the current working directory, use GetCurrentDirectory instead of _getcwd.
1346 //
1347 // In the path utility functions inside the JSC shell, we does not handle the UNC and UNCW including the network host name.
1348 DWORD bufferLength = ::GetCurrentDirectoryW(0, nullptr);
1349 if (!bufferLength)
1350 return false;
1351 // In Windows, wchar_t is the UTF-16LE.
1352 // https://msdn.microsoft.com/en-us/library/dd374081.aspx
1353 // https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407.aspx
1354 auto buffer = std::make_unique<wchar_t[]>(bufferLength);
1355 DWORD lengthNotIncludingNull = ::GetCurrentDirectoryW(bufferLength, buffer.get());
1356 static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
1357 String directoryString = String(reinterpret_cast<UChar*>(buffer.get()));
1358 // We don't support network path like \\host\share\<path name>.
1359 if (directoryString.startsWith("\\\\"))
1360 return false;
1361#else
1362 auto buffer = std::make_unique<char[]>(PATH_MAX);
1363 if (!getcwd(buffer.get(), PATH_MAX))
1364 return false;
1365 String directoryString = String::fromUTF8(buffer.get());
1366#endif
1367 if (directoryString.isEmpty())
1368 return false;
1369
1370 if (directoryString[directoryString.length() - 1] == pathSeparator())
1371 return extractDirectoryName(directoryString, directoryName);
1372 // Append the seperator to represents the file name. extractDirectoryName only accepts the absolute file name.
1373 return extractDirectoryName(makeString(directoryString, pathSeparator()), directoryName);
1374}
1375
1376static String resolvePath(const DirectoryName& directoryName, const ModuleName& moduleName)
1377{
1378 Vector<String> directoryPieces;
1379 directoryName.queryName.split(pathSeparator(), false, directoryPieces);
1380
1381 // Only first '/' is recognized as the path from the root.
1382 if (moduleName.startsWithRoot())
1383 directoryPieces.clear();
1384
1385 for (const auto& query : moduleName.queries) {
1386 if (query == String(ASCIILiteral(".."))) {
1387 if (!directoryPieces.isEmpty())
1388 directoryPieces.removeLast();
1389 } else if (!query.isEmpty() && query != String(ASCIILiteral(".")))
1390 directoryPieces.append(query);
1391 }
1392
1393 StringBuilder builder;
1394 builder.append(directoryName.rootName);
1395 for (size_t i = 0; i < directoryPieces.size(); ++i) {
1396 builder.append(directoryPieces[i]);
1397 if (i + 1 != directoryPieces.size())
1398 builder.append(pathSeparator());
1399 }
1400 return builder.toString();
1401}
1402
1403JSInternalPromise* GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue)
1404{
1405 VM& vm = globalObject->vm();
1406 auto scope = DECLARE_CATCH_SCOPE(vm);
1407
1408 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1409 const Identifier key = keyValue.toPropertyKey(exec);
1410 if (UNLIKELY(scope.exception())) {
1411 JSValue exception = scope.exception();
1412 scope.clearException();
1413 return deferred->reject(exec, exception);
1414 }
1415
1416 if (key.isSymbol())
1417 return deferred->resolve(exec, keyValue);
1418
1419 DirectoryName directoryName;
1420 if (referrerValue.isUndefined()) {
1421 if (!currentWorkingDirectory(directoryName))
1422 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1423 } else {
1424 const Identifier referrer = referrerValue.toPropertyKey(exec);
1425 if (UNLIKELY(scope.exception())) {
1426 JSValue exception = scope.exception();
1427 scope.clearException();
1428 return deferred->reject(exec, exception);
1429 }
1430 if (referrer.isSymbol()) {
1431 if (!currentWorkingDirectory(directoryName))
1432 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
1433 } else {
1434 // If the referrer exists, we assume that the referrer is the correct absolute path.
1435 if (!extractDirectoryName(referrer.impl(), directoryName))
1436 return deferred->reject(exec, createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
1437 }
1438 }
1439
1440 return deferred->resolve(exec, jsString(exec, resolvePath(directoryName, ModuleName(key.impl()))));
1441}
1442
1443static void convertShebangToJSComment(Vector<char>& buffer)
1444{
1445 if (buffer.size() >= 2) {
1446 if (buffer[0] == '#' && buffer[1] == '!')
1447 buffer[0] = buffer[1] = '/';
1448 }
1449}
1450
1451static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
1452{
1453 // We might have injected "use strict"; at the top.
1454 size_t initialSize = buffer.size();
1455 fseek(file, 0, SEEK_END);
1456 size_t bufferCapacity = ftell(file);
1457 fseek(file, 0, SEEK_SET);
1458 buffer.resize(bufferCapacity + initialSize);
1459 size_t readSize = fread(buffer.data() + initialSize, 1, buffer.size(), file);
1460 return readSize == buffer.size() - initialSize;
1461}
1462
1463static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1464{
1465 FILE* f = fopen(fileName.utf8().data(), "rb");
1466 if (!f) {
1467 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1468 return false;
1469 }
1470
1471 bool result = fillBufferWithContentsOfFile(f, buffer);
1472 fclose(f);
1473
1474 return result;
1475}
1476
1477static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1478{
1479 if (!fillBufferWithContentsOfFile(fileName, buffer))
1480 return false;
1481 convertShebangToJSComment(buffer);
1482 return true;
1483}
1484
1485static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
1486{
1487 // We assume that fileName is always an absolute path.
1488#if OS(WINDOWS)
1489 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath
1490 // Use long UNC to pass the long path name to the Windows APIs.
1491 String longUNCPathName = WTF::makeString("\\\\?\\", fileName);
1492 static_assert(sizeof(wchar_t) == sizeof(UChar), "In Windows, both are UTF-16LE");
1493 auto utf16Vector = longUNCPathName.charactersWithNullTermination();
1494 FILE* f = _wfopen(reinterpret_cast<wchar_t*>(utf16Vector.data()), L"rb");
1495#else
1496 FILE* f = fopen(fileName.utf8().data(), "r");
1497#endif
1498 if (!f) {
1499 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1500 return false;
1501 }
1502
1503 bool result = fillBufferWithContentsOfFile(f, buffer);
1504 if (result)
1505 convertShebangToJSComment(buffer);
1506 fclose(f);
1507
1508 return result;
1509}
1510
1511JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue key, JSValue)
1512{
1513 VM& vm = globalObject->vm();
1514 auto scope = DECLARE_CATCH_SCOPE(vm);
1515 JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
1516 String moduleKey = key.toWTFString(exec);
1517 if (UNLIKELY(scope.exception())) {
1518 JSValue exception = scope.exception();
1519 scope.clearException();
1520 return deferred->reject(exec, exception);
1521 }
1522
1523 // Here, now we consider moduleKey as the fileName.
1524 Vector<char> utf8;
1525 if (!fetchModuleFromLocalFileSystem(moduleKey, utf8))
1526 return deferred->reject(exec, createError(exec, makeString("Could not open file '", moduleKey, "'.")));
1527
1528 return deferred->resolve(exec, jsString(exec, stringFromUTF(utf8)));
1529}
1530
1531
1532static EncodedJSValue printInternal(ExecState* exec, FILE* out)
1533{
1534 VM& vm = exec->vm();
1535 auto scope = DECLARE_THROW_SCOPE(vm);
1536
1537 if (test262AsyncTest) {
1538 JSValue value = exec->argument(0);
1539 if (value.isString() && WTF::equal(asString(value)->value(exec).impl(), "Test262:AsyncTestComplete"))
1540 test262AsyncPassed = true;
1541 return JSValue::encode(jsUndefined());
1542 }
1543
1544 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
1545 if (i)
1546 if (EOF == fputc(' ', out))
1547 goto fail;
1548
1549 auto viewWithString = exec->uncheckedArgument(i).toString(exec)->viewWithUnderlyingString(*exec);
1550 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1551 if (fprintf(out, "%s", viewWithString.view.utf8().data()) < 0)
1552 goto fail;
1553 }
1554
1555 fputc('\n', out);
1556fail:
1557 fflush(out);
1558 return JSValue::encode(jsUndefined());
1559}
1560
1561EncodedJSValue JSC_HOST_CALL functionPrintStdOut(ExecState* exec) { return printInternal(exec, stdout); }
1562EncodedJSValue JSC_HOST_CALL functionPrintStdErr(ExecState* exec) { return printInternal(exec, stderr); }
1563
1564#ifndef NDEBUG
1565EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
1566{
1567 VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
1568 ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
1569 if (callerFrame)
1570 exec->vm().interpreter->dumpCallFrame(callerFrame);
1571 return JSValue::encode(jsUndefined());
1572}
1573#endif
1574
1575EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
1576{
1577 VM& vm = exec->vm();
1578 auto scope = DECLARE_THROW_SCOPE(vm);
1579 auto viewWithString = exec->argument(0).toString(exec)->viewWithUnderlyingString(*exec);
1580 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1581 fprintf(stderr, "--> %s\n", viewWithString.view.utf8().data());
1582 return JSValue::encode(jsUndefined());
1583}
1584
1585EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
1586{
1587 if (exec->argumentCount() < 1)
1588 return JSValue::encode(jsUndefined());
1589 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
1590}
1591
1592EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
1593{
1594 if (exec->argumentCount() < 1)
1595 return JSValue::encode(jsUndefined());
1596 JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
1597 if (!object)
1598 return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
1599 return JSValue::encode(jsNontrivialString(exec, toString("<Butterfly: ", RawPointer(object->butterfly()), "; public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
1600}
1601
1602EncodedJSValue JSC_HOST_CALL functionSleepSeconds(ExecState* exec)
1603{
1604 if (exec->argumentCount() >= 1)
1605 sleep(exec->argument(0).toNumber(exec));
1606 return JSValue::encode(jsUndefined());
1607}
1608
1609class FunctionJSCStackFunctor {
1610public:
1611 FunctionJSCStackFunctor(StringBuilder& trace)
1612 : m_trace(trace)
1613 {
1614 }
1615
1616 StackVisitor::Status operator()(StackVisitor& visitor) const
1617 {
1618 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
1619 return StackVisitor::Continue;
1620 }
1621
1622private:
1623 StringBuilder& m_trace;
1624};
1625
1626EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
1627{
1628 StringBuilder trace;
1629 trace.appendLiteral("--> Stack trace:\n");
1630
1631 FunctionJSCStackFunctor functor(trace);
1632 exec->iterate(functor);
1633 fprintf(stderr, "%s", trace.toString().utf8().data());
1634 return JSValue::encode(jsUndefined());
1635}
1636
1637EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
1638{
1639 JSLockHolder lock(exec);
1640 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
1641}
1642
1643EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
1644{
1645 VM& vm = exec->vm();
1646 JSLockHolder lock(vm);
1647 auto scope = DECLARE_THROW_SCOPE(vm);
1648
1649 Root* root = jsDynamicCast<Root*>(exec->argument(0));
1650 if (!root)
1651 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Cannot create Element without a Root."))));
1652 return JSValue::encode(Element::create(vm, exec->lexicalGlobalObject(), root));
1653}
1654
1655EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
1656{
1657 JSLockHolder lock(exec);
1658 Root* root = jsDynamicCast<Root*>(exec->argument(0));
1659 if (!root)
1660 return JSValue::encode(jsUndefined());
1661 Element* result = root->element();
1662 return JSValue::encode(result ? result : jsUndefined());
1663}
1664
1665EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
1666{
1667 JSLockHolder lock(exec);
1668 Element* element = jsDynamicCast<Element*>(exec->argument(0));
1669 Root* root = jsDynamicCast<Root*>(exec->argument(1));
1670 if (element && root)
1671 element->setRoot(exec->vm(), root);
1672 return JSValue::encode(jsUndefined());
1673}
1674
1675EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec)
1676{
1677 JSLockHolder lock(exec);
1678 return JSValue::encode(SimpleObject::create(exec->vm(), exec->lexicalGlobalObject()));
1679}
1680
1681EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec)
1682{
1683 VM& vm = exec->vm();
1684 JSLockHolder lock(vm);
1685 auto scope = DECLARE_THROW_SCOPE(vm);
1686
1687 SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(exec->argument(0));
1688 if (UNLIKELY(!simpleObject)) {
1689 throwTypeError(exec, scope, ASCIILiteral("Invalid use of getHiddenValue test function"));
1690 return encodedJSValue();
1691 }
1692 return JSValue::encode(simpleObject->hiddenValue());
1693}
1694
1695EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec)
1696{
1697 VM& vm = exec->vm();
1698 JSLockHolder lock(vm);
1699 auto scope = DECLARE_THROW_SCOPE(vm);
1700
1701 SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(exec->argument(0));
1702 if (UNLIKELY(!simpleObject)) {
1703 throwTypeError(exec, scope, ASCIILiteral("Invalid use of setHiddenValue test function"));
1704 return encodedJSValue();
1705 }
1706 JSValue value = exec->argument(1);
1707 simpleObject->setHiddenValue(exec->vm(), value);
1708 return JSValue::encode(jsUndefined());
1709}
1710
1711EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
1712{
1713 JSLockHolder lock(exec);
1714 JSValue target = exec->argument(0);
1715 if (!target.isObject())
1716 return JSValue::encode(jsUndefined());
1717 JSObject* jsTarget = asObject(target.asCell());
1718 Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->getPrototypeDirect(), ImpureProxyType);
1719 JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
1720 return JSValue::encode(proxy);
1721}
1722
1723EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
1724{
1725 JSLockHolder lock(exec);
1726 RuntimeArray* array = RuntimeArray::create(exec);
1727 return JSValue::encode(array);
1728}
1729
1730EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
1731{
1732 JSLockHolder lock(exec);
1733 JSValue target = exec->argument(0);
1734 JSObject* delegate = nullptr;
1735 if (target.isObject())
1736 delegate = asObject(target.asCell());
1737 Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1738 ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
1739 return JSValue::encode(result);
1740}
1741
1742EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec)
1743{
1744 JSLockHolder lock(exec);
1745 Structure* structure = CustomGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1746 CustomGetter* result = CustomGetter::create(exec->vm(), structure);
1747 return JSValue::encode(result);
1748}
1749
1750EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec)
1751{
1752 JSLockHolder lock(exec);
1753 Structure* structure = DOMJITNode::createStructure(exec->vm(), exec->lexicalGlobalObject(), DOMJITGetter::create(exec->vm(), DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull())));
1754 DOMJITNode* result = DOMJITNode::create(exec->vm(), structure);
1755 return JSValue::encode(result);
1756}
1757
1758EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec)
1759{
1760 JSLockHolder lock(exec);
1761 Structure* structure = DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1762 DOMJITGetter* result = DOMJITGetter::create(exec->vm(), structure);
1763 return JSValue::encode(result);
1764}
1765
1766EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec)
1767{
1768 JSLockHolder lock(exec);
1769 Structure* structure = DOMJITGetterComplex::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1770 DOMJITGetterComplex* result = DOMJITGetterComplex::create(exec->vm(), exec->lexicalGlobalObject(), structure);
1771 return JSValue::encode(result);
1772}
1773
1774EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState* exec)
1775{
1776 JSLockHolder lock(exec);
1777 Structure* structure = DOMJITFunctionObject::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
1778 DOMJITFunctionObject* result = DOMJITFunctionObject::create(exec->vm(), exec->lexicalGlobalObject(), structure);
1779 return JSValue::encode(result);
1780}
1781
1782EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
1783{
1784 VM& vm = exec->vm();
1785 JSLockHolder lock(vm);
1786 auto scope = DECLARE_THROW_SCOPE(vm);
1787
1788 JSValue base = exec->argument(0);
1789 if (!base.isObject())
1790 return JSValue::encode(jsUndefined());
1791 JSValue delegate = exec->argument(1);
1792 if (!delegate.isObject())
1793 return JSValue::encode(jsUndefined());
1794 ImpureGetter* impureGetter = jsDynamicCast<ImpureGetter*>(asObject(base.asCell()));
1795 if (UNLIKELY(!impureGetter)) {
1796 throwTypeError(exec, scope, ASCIILiteral("argument is not an ImpureGetter"));
1797 return encodedJSValue();
1798 }
1799 impureGetter->setDelegate(vm, asObject(delegate.asCell()));
1800 return JSValue::encode(jsUndefined());
1801}
1802
1803EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
1804{
1805 JSLockHolder lock(exec);
1806 exec->heap()->collectAllGarbage();
1807 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1808}
1809
1810EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
1811{
1812 JSLockHolder lock(exec);
1813 exec->heap()->collectSync(CollectionScope::Full);
1814 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
1815}
1816
1817EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
1818{
1819 JSLockHolder lock(exec);
1820 exec->heap()->collectSync(CollectionScope::Eden);
1821 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastEdenCollection()));
1822}
1823
1824EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*)
1825{
1826 // It's best for this to be the first thing called in the
1827 // JS program so the option is set to true before we JIT.
1828 Options::forceGCSlowPaths() = true;
1829 return JSValue::encode(jsUndefined());
1830}
1831
1832EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
1833{
1834 JSLockHolder lock(exec);
1835 return JSValue::encode(jsNumber(exec->heap()->size()));
1836}
1837
1838// This function is not generally very helpful in 64-bit code as the tag and payload
1839// share a register. But in 32-bit JITed code the tag may not be checked if an
1840// optimization removes type checking requirements, such as in ===.
1841EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState* exec)
1842{
1843 JSValue value = exec->argument(0);
1844 if (!value.isCell())
1845 return JSValue::encode(jsUndefined());
1846 // Need to cast to uint64_t so bitwise_cast will play along.
1847 uint64_t asNumber = reinterpret_cast<uint64_t>(value.asCell());
1848 EncodedJSValue returnValue = JSValue::encode(jsNumber(bitwise_cast<double>(asNumber)));
1849 return returnValue;
1850}
1851
1852static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState* exec)
1853{
1854 JSValue value = exec->argument(0);
1855 if (!value.isObject())
1856 return JSValue::encode(jsUndefined());
1857
1858 JSValue property = exec->argument(1);
1859 if (!property.isString())
1860 return JSValue::encode(jsUndefined());
1861
1862 Identifier ident = Identifier::fromString(&exec->vm(), property.toWTFString(exec));
1863
1864 PropertySlot slot(value, PropertySlot::InternalMethodType::VMInquiry);
1865 value.getPropertySlot(exec, ident, slot);
1866
1867 JSValue result;
1868 if (slot.isCacheableGetter())
1869 result = slot.getterSetter();
1870 else
1871 result = jsNull();
1872
1873 return JSValue::encode(result);
1874}
1875
1876EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
1877{
1878 // We need this function for compatibility with the Mozilla JS tests but for now
1879 // we don't actually do any version-specific handling
1880 return JSValue::encode(jsUndefined());
1881}
1882
1883EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
1884{
1885 VM& vm = exec->vm();
1886 auto scope = DECLARE_THROW_SCOPE(vm);
1887
1888 String fileName = exec->argument(0).toWTFString(exec);
1889 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1890 Vector<char> script;
1891 if (!fetchScriptFromLocalFileSystem(fileName, script))
1892 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
1893
1894 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
1895
1896 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
1897 for (unsigned i = 1; i < exec->argumentCount(); ++i)
1898 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
1899 globalObject->putDirect(
1900 vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
1901
1902 NakedPtr<Exception> exception;
1903 StopWatch stopWatch;
1904 stopWatch.start();
1905 evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), exception);
1906 stopWatch.stop();
1907
1908 if (exception) {
1909 throwException(globalObject->globalExec(), scope, exception);
1910 return JSValue::encode(jsUndefined());
1911 }
1912
1913 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
1914}
1915
1916EncodedJSValue JSC_HOST_CALL functionRunString(ExecState* exec)
1917{
1918 VM& vm = exec->vm();
1919 auto scope = DECLARE_THROW_SCOPE(vm);
1920
1921 String source = exec->argument(0).toWTFString(exec);
1922 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1923
1924 GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
1925
1926 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
1927 for (unsigned i = 1; i < exec->argumentCount(); ++i)
1928 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
1929 globalObject->putDirect(
1930 vm, Identifier::fromString(globalObject->globalExec(), "arguments"), array);
1931
1932 NakedPtr<Exception> exception;
1933 evaluate(globalObject->globalExec(), makeSource(source), JSValue(), exception);
1934
1935 if (exception) {
1936 scope.throwException(globalObject->globalExec(), exception);
1937 return JSValue::encode(jsUndefined());
1938 }
1939
1940 return JSValue::encode(globalObject);
1941}
1942
1943EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
1944{
1945 VM& vm = exec->vm();
1946 auto scope = DECLARE_THROW_SCOPE(vm);
1947
1948 String fileName = exec->argument(0).toWTFString(exec);
1949 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1950 Vector<char> script;
1951 if (!fetchScriptFromLocalFileSystem(fileName, script))
1952 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
1953
1954 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1955
1956 NakedPtr<Exception> evaluationException;
1957 JSValue result = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), evaluationException);
1958 if (evaluationException)
1959 throwException(exec, scope, evaluationException);
1960 return JSValue::encode(result);
1961}
1962
1963EncodedJSValue JSC_HOST_CALL functionLoadString(ExecState* exec)
1964{
1965 VM& vm = exec->vm();
1966 auto scope = DECLARE_THROW_SCOPE(vm);
1967
1968 String sourceCode = exec->argument(0).toWTFString(exec);
1969 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1970 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
1971
1972 NakedPtr<Exception> evaluationException;
1973 JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode), JSValue(), evaluationException);
1974 if (evaluationException)
1975 throwException(exec, scope, evaluationException);
1976 return JSValue::encode(result);
1977}
1978
1979EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
1980{
1981 VM& vm = exec->vm();
1982 auto scope = DECLARE_THROW_SCOPE(vm);
1983
1984 String fileName = exec->argument(0).toWTFString(exec);
1985 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1986
1987 bool isBinary = false;
1988 if (exec->argumentCount() > 1) {
1989 String type = exec->argument(1).toWTFString(exec);
1990 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1991 if (type != "binary")
1992 return throwVMError(exec, scope, "Expected 'binary' as second argument.");
1993 isBinary = true;
1994 }
1995
1996 Vector<char> content;
1997 if (!fillBufferWithContentsOfFile(fileName, content))
1998 return throwVMError(exec, scope, "Could not open file.");
1999
2000 if (!isBinary)
2001 return JSValue::encode(jsString(exec, stringFromUTF(content)));
2002
2003 Structure* structure = exec->lexicalGlobalObject()->typedArrayStructure(TypeUint8);
2004 auto length = content.size();
2005 JSObject* result = createUint8TypedArray(exec, structure, ArrayBuffer::createFromBytes(content.releaseBuffer().leakPtr(), length, [] (void* p) { fastFree(p); }), 0, length);
2006 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2007
2008 return JSValue::encode(result);
2009}
2010
2011EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
2012{
2013 VM& vm = exec->vm();
2014 auto scope = DECLARE_THROW_SCOPE(vm);
2015
2016 String fileName = exec->argument(0).toWTFString(exec);
2017 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2018 Vector<char> script;
2019 if (!fetchScriptFromLocalFileSystem(fileName, script))
2020 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2021
2022 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
2023
2024 StopWatch stopWatch;
2025 stopWatch.start();
2026
2027 JSValue syntaxException;
2028 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, fileName), &syntaxException);
2029 stopWatch.stop();
2030
2031 if (!validSyntax)
2032 throwException(exec, scope, syntaxException);
2033 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2034}
2035
2036#if ENABLE(SAMPLING_FLAGS)
2037EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
2038{
2039 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2040 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
2041 if ((flag >= 1) && (flag <= 32))
2042 SamplingFlags::setFlag(flag);
2043 }
2044 return JSValue::encode(jsNull());
2045}
2046
2047EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
2048{
2049 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2050 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
2051 if ((flag >= 1) && (flag <= 32))
2052 SamplingFlags::clearFlag(flag);
2053 }
2054 return JSValue::encode(jsNull());
2055}
2056#endif
2057
2058EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState* exec)
2059{
2060 return JSValue::encode(exec->vm().shadowChicken().functionsOnStack(exec));
2061}
2062
2063EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState* exec)
2064{
2065 exec->vm().setGlobalConstRedeclarationShouldThrow(false);
2066 return JSValue::encode(jsUndefined());
2067}
2068
2069EncodedJSValue JSC_HOST_CALL functionGetRandomSeed(ExecState* exec)
2070{
2071 return JSValue::encode(jsNumber(exec->lexicalGlobalObject()->weakRandom().seed()));
2072}
2073
2074EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState* exec)
2075{
2076 VM& vm = exec->vm();
2077 auto scope = DECLARE_THROW_SCOPE(vm);
2078
2079 unsigned seed = exec->argument(0).toUInt32(exec);
2080 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2081 exec->lexicalGlobalObject()->weakRandom().setSeed(seed);
2082 return JSValue::encode(jsUndefined());
2083}
2084
2085EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState* exec)
2086{
2087 JSValue argument = exec->argument(0);
2088 if (!argument.isString())
2089 return JSValue::encode(jsBoolean(false));
2090 const StringImpl* impl = jsCast<JSString*>(argument)->tryGetValueImpl();
2091 return JSValue::encode(jsBoolean(!impl));
2092}
2093
2094EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
2095{
2096 Vector<char, 256> line;
2097 int c;
2098 while ((c = getchar()) != EOF) {
2099 // FIXME: Should we also break on \r?
2100 if (c == '\n')
2101 break;
2102 line.append(c);
2103 }
2104 line.append('\0');
2105 return JSValue::encode(jsString(exec, line.data()));
2106}
2107
2108EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
2109{
2110 return JSValue::encode(jsNumber(currentTime()));
2111}
2112
2113EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
2114{
2115 return JSValue::encode(setNeverInline(exec));
2116}
2117
2118EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState* exec)
2119{
2120 return JSValue::encode(setNeverOptimize(exec));
2121}
2122
2123EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState* exec)
2124{
2125 if (JSFunction* function = jsDynamicCast<JSFunction*>(exec->argument(0))) {
2126 FunctionExecutable* executable = function->jsExecutable();
2127 executable->setNeverFTLOptimize(true);
2128 }
2129
2130 return JSValue::encode(jsUndefined());
2131}
2132
2133EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState* exec)
2134{
2135 return JSValue::encode(setCannotUseOSRExitFuzzing(exec));
2136}
2137
2138EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
2139{
2140 return JSValue::encode(optimizeNextInvocation(exec));
2141}
2142
2143EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
2144{
2145 return JSValue::encode(numberOfDFGCompiles(exec));
2146}
2147
2148template<typename ValueType>
2149typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, Identifier, ValueType) { }
2150
2151template<typename ValueType>
2152typename std::enable_if<std::is_fundamental<ValueType>::value>::type addOption(VM& vm, JSObject* optionsObject, Identifier identifier, ValueType value)
2153{
2154 optionsObject->putDirect(vm, identifier, JSValue(value));
2155}
2156
2157EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState* exec)
2158{
2159 JSObject* optionsObject = constructEmptyObject(exec);
2160#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
2161 addOption(exec->vm(), optionsObject, Identifier::fromString(exec, #name_), Options::name_());
2162 JSC_OPTIONS(FOR_EACH_OPTION)
2163#undef FOR_EACH_OPTION
2164 return JSValue::encode(optionsObject);
2165}
2166
2167EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
2168{
2169 if (exec->argumentCount() < 1)
2170 return JSValue::encode(jsUndefined());
2171
2172 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
2173 if (!block)
2174 return JSValue::encode(jsNumber(0));
2175
2176 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
2177}
2178
2179EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
2180{
2181 VM& vm = exec->vm();
2182 auto scope = DECLARE_THROW_SCOPE(vm);
2183
2184 if (exec->argumentCount() < 1)
2185 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Not enough arguments"))));
2186
2187 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
2188 if (!buffer)
2189 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected an array buffer"))));
2190
2191 ArrayBufferContents dummyContents;
2192 buffer->impl()->transferTo(dummyContents);
2193
2194 return JSValue::encode(jsUndefined());
2195}
2196
2197EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState* exec)
2198{
2199 exec->vm().setFailNextNewCodeBlock();
2200 return JSValue::encode(jsUndefined());
2201}
2202
2203EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
2204{
2205 jscExit(EXIT_SUCCESS);
2206
2207#if COMPILER(MSVC)
2208 // Without this, Visual Studio will complain that this method does not return a value.
2209 return JSValue::encode(jsUndefined());
2210#endif
2211}
2212
2213EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*)
2214{
2215 CRASH();
2216}
2217
2218EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
2219EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
2220
2221EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
2222EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
2223EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
2224{
2225 for (size_t i = 0; i < exec->argumentCount(); ++i) {
2226 if (!exec->argument(i).isInt32())
2227 return JSValue::encode(jsBoolean(false));
2228 }
2229 return JSValue::encode(jsBoolean(true));
2230}
2231
2232EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
2233
2234EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
2235{
2236 return JSValue::encode(jsNumber(42));
2237}
2238
2239EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
2240{
2241 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
2242}
2243
2244EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
2245{
2246 JSValue value = exec->argument(0);
2247 if (value.isObject())
2248 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
2249 return JSValue::encode(jsBoolean(false));
2250}
2251
2252EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
2253{
2254 exec->vm().dumpTypeProfilerData();
2255 return JSValue::encode(jsUndefined());
2256}
2257
2258EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
2259{
2260 RELEASE_ASSERT(exec->vm().typeProfiler());
2261 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
2262
2263 JSValue functionValue = exec->argument(0);
2264 RELEASE_ASSERT(functionValue.isFunction());
2265 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
2266
2267 RELEASE_ASSERT(exec->argument(1).isString());
2268 String substring = exec->argument(1).getString(exec);
2269 String sourceCodeText = executable->source().view().toString();
2270 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
2271
2272 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
2273 return JSValue::encode(JSONParse(exec, jsonString));
2274}
2275
2276EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
2277{
2278 RELEASE_ASSERT(exec->vm().typeProfiler());
2279 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
2280
2281 JSValue functionValue = exec->argument(0);
2282 RELEASE_ASSERT(functionValue.isFunction());
2283 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
2284
2285 unsigned offset = executable->typeProfilingStartOffset();
2286 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
2287 return JSValue::encode(JSONParse(exec, jsonString));
2288}
2289
2290EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
2291{
2292 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
2293 exec->vm().controlFlowProfiler()->dumpData();
2294 return JSValue::encode(jsUndefined());
2295}
2296
2297EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
2298{
2299 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
2300
2301 JSValue functionValue = exec->argument(0);
2302 RELEASE_ASSERT(functionValue.isFunction());
2303 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
2304
2305 RELEASE_ASSERT(exec->argument(1).isString());
2306 String substring = exec->argument(1).getString(exec);
2307 String sourceCodeText = executable->source().view().toString();
2308 RELEASE_ASSERT(sourceCodeText.contains(substring));
2309 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
2310
2311 bool hasExecuted = exec->vm().controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), exec->vm());
2312 return JSValue::encode(jsBoolean(hasExecuted));
2313}
2314
2315EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec)
2316{
2317 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
2318
2319 JSValue functionValue = exec->argument(0);
2320 RELEASE_ASSERT(functionValue.isFunction());
2321 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
2322
2323 RELEASE_ASSERT(exec->argument(1).isString());
2324 String substring = exec->argument(1).getString(exec);
2325 String sourceCodeText = executable->source().view().toString();
2326 RELEASE_ASSERT(sourceCodeText.contains(substring));
2327 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
2328
2329 size_t executionCount = exec->vm().controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), exec->vm());
2330 return JSValue::encode(JSValue(executionCount));
2331}
2332
2333EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
2334{
2335 Options::useExceptionFuzz() = true;
2336 return JSValue::encode(jsUndefined());
2337}
2338
2339EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState* exec)
2340{
2341 exec->vm().drainMicrotasks();
2342 return JSValue::encode(jsUndefined());
2343}
2344
2345EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*)
2346{
2347#if USE(JSVALUE64)
2348 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
2349#else
2350 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
2351#endif
2352}
2353
2354EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
2355{
2356 VM& vm = exec->vm();
2357 auto scope = DECLARE_THROW_SCOPE(vm);
2358
2359 String fileName = exec->argument(0).toWTFString(exec);
2360 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2361 Vector<char> script;
2362 if (!fetchScriptFromLocalFileSystem(fileName, script))
2363 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Could not open file."))));
2364
2365 JSInternalPromise* promise = loadAndEvaluateModule(exec, fileName);
2366 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2367
2368 JSValue error;
2369 JSFunction* errorHandler = JSNativeStdFunction::create(vm, exec->lexicalGlobalObject(), 1, String(), [&](ExecState* exec) {
2370 error = exec->argument(0);
2371 return JSValue::encode(jsUndefined());
2372 });
2373
2374 promise->then(exec, nullptr, errorHandler);
2375 vm.drainMicrotasks();
2376 if (error)
2377 return JSValue::encode(throwException(exec, scope, error));
2378 return JSValue::encode(jsUndefined());
2379}
2380
2381EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState* exec)
2382{
2383 VM& vm = exec->vm();
2384 auto scope = DECLARE_THROW_SCOPE(vm);
2385
2386 if (exec->argumentCount() < 1 || !exec->argument(0).isString())
2387 return JSValue::encode(jsUndefined());
2388
2389 String functionText = exec->argument(0).toWTFString(exec);
2390 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2391
2392 const SourceCode& source = makeSource(functionText);
2393 JSFunction* func = JSFunction::createBuiltinFunction(vm, createBuiltinExecutable(vm, source, Identifier::fromString(&vm, "foo"), ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, source), exec->lexicalGlobalObject());
2394
2395 return JSValue::encode(func);
2396}
2397
2398EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
2399{
2400 VM& vm = exec->vm();
2401 return JSValue::encode(GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>()));
2402}
2403
2404EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState* exec)
2405{
2406 VM& vm = exec->vm();
2407 auto scope = DECLARE_THROW_SCOPE(vm);
2408
2409 String source = exec->argument(0).toWTFString(exec);
2410 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2411
2412 StopWatch stopWatch;
2413 stopWatch.start();
2414
2415 ParserError error;
2416 bool validSyntax = checkModuleSyntax(exec, makeSource(source, String(), TextPosition::minimumPosition(), SourceProviderSourceType::Module), error);
2417 stopWatch.stop();
2418
2419 if (!validSyntax)
2420 throwException(exec, scope, jsNontrivialString(exec, toString("SyntaxError: ", error.message(), ":", error.line())));
2421 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
2422}
2423
2424EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*)
2425{
2426#if ENABLE(SAMPLING_PROFILER)
2427 return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
2428#else
2429 return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
2430#endif
2431}
2432
2433EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState* exec)
2434{
2435 VM& vm = exec->vm();
2436 JSLockHolder lock(vm);
2437 auto scope = DECLARE_THROW_SCOPE(vm);
2438
2439 HeapSnapshotBuilder snapshotBuilder(exec->vm().ensureHeapProfiler());
2440 snapshotBuilder.buildSnapshot();
2441
2442 String jsonString = snapshotBuilder.json();
2443 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
2444 RELEASE_ASSERT(!scope.exception());
2445 return result;
2446}
2447
2448EncodedJSValue JSC_HOST_CALL functionResetSuperSamplerState(ExecState*)
2449{
2450 resetSuperSamplerState();
2451 return JSValue::encode(jsUndefined());
2452}
2453
2454EncodedJSValue JSC_HOST_CALL functionEnsureArrayStorage(ExecState* exec)
2455{
2456 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
2457 if (JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0)))
2458 object->ensureArrayStorage(exec->vm());
2459 }
2460 return JSValue::encode(jsUndefined());
2461}
2462
2463#if ENABLE(SAMPLING_PROFILER)
2464EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState* exec)
2465{
2466 SamplingProfiler& samplingProfiler = exec->vm().ensureSamplingProfiler(WTF::Stopwatch::create());
2467 samplingProfiler.noticeCurrentThreadAsJSCExecutionThread();
2468 samplingProfiler.start();
2469 return JSValue::encode(jsUndefined());
2470}
2471
2472EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState* exec)
2473{
2474 VM& vm = exec->vm();
2475 auto scope = DECLARE_THROW_SCOPE(vm);
2476
2477 if (!vm.samplingProfiler())
2478 return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Sampling profiler was never started"))));
2479
2480 String jsonString = vm.samplingProfiler()->stackTracesAsJSON();
2481 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
2482 RELEASE_ASSERT(!scope.exception());
2483 return result;
2484}
2485#endif // ENABLE(SAMPLING_PROFILER)
2486
2487#if ENABLE(WEBASSEMBLY)
2488
2489static JSValue box(ExecState* exec, VM& vm, JSValue wasmValue)
2490{
2491 JSString* type = jsCast<JSString*>(wasmValue.get(exec, makeIdentifier(vm, "type")));
2492 JSValue value = wasmValue.get(exec, makeIdentifier(vm, "value"));
2493
2494 const String& typeString = type->value(exec);
2495 if (typeString == "i64") {
2496 RELEASE_ASSERT(value.isString());
2497 int64_t result;
2498 RELEASE_ASSERT(sscanf(bitwise_cast<const char*>(jsCast<JSString*>(value)->value(exec).characters8()), "%lld", &result) != EOF);
2499 return JSValue::decode(result);
2500 }
2501 RELEASE_ASSERT(value.isNumber());
2502
2503 if (typeString == "i32") {
2504 RELEASE_ASSERT(value.isInt32());
2505 return JSValue::decode(static_cast<uint32_t>(value.asInt32()));
2506 }
2507
2508 if (typeString == "f32")
2509 return JSValue::decode(bitwise_cast<uint32_t>(value.toFloat(exec)));
2510
2511 RELEASE_ASSERT(typeString == "f64");
2512 return value;
2513}
2514
2515static JSValue callWasmFunction(VM* vm, const B3::Compilation& code, Vector<JSValue>& boxedArgs)
2516{
2517 JSValue firstArgument;
2518 int argCount = 1;
2519 JSValue* remainingArgs = nullptr;
2520 if (boxedArgs.size()) {
2521 remainingArgs = boxedArgs.data();
2522 firstArgument = *remainingArgs;
2523 remainingArgs++;
2524 argCount = boxedArgs.size();
2525 }
2526
2527 ProtoCallFrame protoCallFrame;
2528 protoCallFrame.init(nullptr, nullptr, firstArgument, argCount, remainingArgs);
2529
2530 return JSValue::decode(vmEntryToWasm(code.code().executableAddress(), vm, &protoCallFrame));
2531}
2532
2533// testWasmModule(JSArrayBufferView source, number functionCount, ...[[WasmValue, [WasmValue]]]) where the ith copy of [[result, [args]]] is a list
2534// of arguments to be passed to the ith wasm function as well as the expected result. WasmValue is an object with "type" and "value" properties.
2535static EncodedJSValue JSC_HOST_CALL functionTestWasmModuleFunctions(ExecState* exec)
2536{
2537 VM& vm = exec->vm();
2538 auto scope = DECLARE_THROW_SCOPE(vm);
2539
2540 if (!Options::useWebAssembly())
2541 return throwVMTypeError(exec, scope, ASCIILiteral("testWasmModule should only be called if the useWebAssembly option is set"));
2542
2543 JSArrayBufferView* source = jsCast<JSArrayBufferView*>(exec->argument(0));
2544 uint32_t functionCount = exec->argument(1).toUInt32(exec);
2545
2546 if (exec->argumentCount() != functionCount + 2)
2547 CRASH();
2548
2549 Wasm::Plan plan(&vm, static_cast<uint8_t*>(source->vector()), source->length());
2550 plan.run();
2551 if (plan.failed())
2552 CRASH();
2553
2554 if (plan.compiledFunctionCount() != functionCount)
2555 CRASH();
2556
2557 for (uint32_t i = 0; i < functionCount; ++i) {
2558 if (!plan.compiledFunction(i))
2559 dataLogLn("failed to compile function at index", i);
2560
2561 JSArray* testCases = jsCast<JSArray*>(exec->argument(i + 2));
2562 for (unsigned testIndex = 0; testIndex < testCases->length(); ++testIndex) {
2563 JSArray* test = jsCast<JSArray*>(testCases->getIndexQuickly(testIndex));
2564 JSObject* result = jsCast<JSObject*>(test->getIndexQuickly(0));
2565 JSArray* arguments = jsCast<JSArray*>(test->getIndexQuickly(1));
2566
2567 Vector<JSValue> boxedArgs;
2568 for (unsigned argIndex = 0; argIndex < arguments->length(); ++argIndex)
2569 boxedArgs.append(box(exec, vm, arguments->getIndexQuickly(argIndex)));
2570
2571 JSValue callResult = callWasmFunction(&vm, *plan.compiledFunction(i)->jsEntryPoint, boxedArgs);
2572 JSValue expected = box(exec, vm, result);
2573 if (callResult != expected) {
2574 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, toCString(" (callResult == ", RawPointer(bitwise_cast<void*>(callResult)), ", expected == ", RawPointer(bitwise_cast<void*>(expected)), ")").data());
2575 CRASH();
2576 }
2577 }
2578 }
2579
2580 return encodedJSUndefined();
2581}
2582
2583#endif // ENABLE(WEBASSEBLY)
2584
2585// Use SEH for Release builds only to get rid of the crash report dialog
2586// (luckily the same tests fail in Release and Debug builds so far). Need to
2587// be in a separate main function because the jscmain function requires object
2588// unwinding.
2589
2590#if COMPILER(MSVC) && !defined(_DEBUG)
2591#define TRY __try {
2592#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
2593#else
2594#define TRY
2595#define EXCEPT(x)
2596#endif
2597
2598int jscmain(int argc, char** argv);
2599
2600static double s_desiredTimeout;
2601static double s_timeoutMultiplier = 1.0;
2602
2603static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
2604{
2605 Seconds timeoutDuration(s_desiredTimeout * s_timeoutMultiplier);
2606 sleep(timeoutDuration);
2607 dataLog("Timed out after ", timeoutDuration, " seconds!\n");
2608 CRASH();
2609}
2610
2611static void startTimeoutThreadIfNeeded()
2612{
2613 if (char* timeoutString = getenv("JSCTEST_timeout")) {
2614 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
2615 dataLog("WARNING: timeout string is malformed, got ", timeoutString,
2616 " but expected a number. Not using a timeout.\n");
2617 } else
2618 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
2619 }
2620}
2621
2622int main(int argc, char** argv)
2623{
2624#if PLATFORM(IOS) && CPU(ARM_THUMB2)
2625 // Enabled IEEE754 denormal support.
2626 fenv_t env;
2627 fegetenv( &env );
2628 env.__fpscr &= ~0x01000000u;
2629 fesetenv( &env );
2630#endif
2631
2632#if OS(WINDOWS)
2633 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
2634 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
2635 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
2636 ::SetErrorMode(0);
2637
2638#if defined(_DEBUG)
2639 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
2640 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2641 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
2642 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
2643 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
2644 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
2645#endif
2646
2647 timeBeginPeriod(1);
2648#endif
2649
2650#if PLATFORM(EFL)
2651 ecore_init();
2652#endif
2653
2654#if PLATFORM(GTK)
2655 if (!setlocale(LC_ALL, ""))
2656 WTFLogAlways("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
2657#endif
2658
2659 // Need to initialize WTF threading before we start any threads. Cannot initialize JSC
2660 // threading yet, since that would do somethings that we'd like to defer until after we
2661 // have a chance to parse options.
2662 WTF::initializeThreading();
2663
2664#if PLATFORM(IOS)
2665 Options::crashIfCantAllocateJITMemory() = true;
2666#endif
2667
2668 // We can't use destructors in the following code because it uses Windows
2669 // Structured Exception Handling
2670 int res = 0;
2671 TRY
2672 res = jscmain(argc, argv);
2673 EXCEPT(res = 3)
2674 finalizeStatsAtEndOfTesting();
2675
2676#if PLATFORM(EFL)
2677 ecore_shutdown();
2678#endif
2679
2680 jscExit(res);
2681}
2682
2683static void dumpException(GlobalObject* globalObject, JSValue exception)
2684{
2685 VM& vm = globalObject->vm();
2686 auto scope = DECLARE_CATCH_SCOPE(vm);
2687
2688#define CHECK_EXCEPTION() do { \
2689 if (scope.exception()) { \
2690 scope.clearException(); \
2691 return; \
2692 } \
2693 } while (false)
2694
2695 printf("Exception: %s\n", exception.toWTFString(globalObject->globalExec()).utf8().data());
2696
2697 Identifier nameID = Identifier::fromString(globalObject->globalExec(), "name");
2698 Identifier fileNameID = Identifier::fromString(globalObject->globalExec(), "sourceURL");
2699 Identifier lineNumberID = Identifier::fromString(globalObject->globalExec(), "line");
2700 Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
2701
2702 JSValue nameValue = exception.get(globalObject->globalExec(), nameID);
2703 CHECK_EXCEPTION();
2704 JSValue fileNameValue = exception.get(globalObject->globalExec(), fileNameID);
2705 CHECK_EXCEPTION();
2706 JSValue lineNumberValue = exception.get(globalObject->globalExec(), lineNumberID);
2707 CHECK_EXCEPTION();
2708 JSValue stackValue = exception.get(globalObject->globalExec(), stackID);
2709 CHECK_EXCEPTION();
2710
2711 if (nameValue.toWTFString(globalObject->globalExec()) == "SyntaxError"
2712 && (!fileNameValue.isUndefinedOrNull() || !lineNumberValue.isUndefinedOrNull())) {
2713 printf(
2714 "at %s:%s\n",
2715 fileNameValue.toWTFString(globalObject->globalExec()).utf8().data(),
2716 lineNumberValue.toWTFString(globalObject->globalExec()).utf8().data());
2717 }
2718
2719 if (!stackValue.isUndefinedOrNull())
2720 printf("%s\n", stackValue.toWTFString(globalObject->globalExec()).utf8().data());
2721
2722#undef CHECK_EXCEPTION
2723}
2724
2725static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, JSValue exception, const String& expectedExceptionName, bool alwaysDumpException)
2726{
2727 auto scope = DECLARE_CATCH_SCOPE(vm);
2728 scope.clearException();
2729 if (!exception) {
2730 printf("Expected uncaught exception with name '%s' but none was thrown\n", expectedExceptionName.utf8().data());
2731 return false;
2732 }
2733
2734 ExecState* exec = globalObject->globalExec();
2735 JSValue exceptionClass = globalObject->get(exec, Identifier::fromString(exec, expectedExceptionName));
2736 if (!exceptionClass.isObject() || scope.exception()) {
2737 printf("Expected uncaught exception with name '%s' but given exception class is not defined\n", expectedExceptionName.utf8().data());
2738 return false;
2739 }
2740
2741 bool isInstanceOfExpectedException = jsCast<JSObject*>(exceptionClass)->hasInstance(exec, exception);
2742 if (scope.exception()) {
2743 printf("Expected uncaught exception with name '%s' but given exception class fails performing hasInstance\n", expectedExceptionName.utf8().data());
2744 return false;
2745 }
2746 if (isInstanceOfExpectedException) {
2747 if (alwaysDumpException)
2748 dumpException(globalObject, exception);
2749 return true;
2750 }
2751
2752 printf("Expected uncaught exception with name '%s' but exception value is not instance of this exception class\n", expectedExceptionName.utf8().data());
2753 dumpException(globalObject, exception);
2754 return false;
2755}
2756
2757static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool module)
2758{
2759 String fileName;
2760 Vector<char> scriptBuffer;
2761
2762 if (dump)
2763 JSC::Options::dumpGeneratedBytecodes() = true;
2764
2765 VM& vm = globalObject->vm();
2766 auto scope = DECLARE_CATCH_SCOPE(vm);
2767 bool success = true;
2768
2769 auto checkException = [&] (bool isLastFile, bool hasException, JSValue value) {
2770 if (!uncaughtExceptionName || !isLastFile) {
2771 success = success && !hasException;
2772 if (dump && !hasException)
2773 printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
2774 if (hasException)
2775 dumpException(globalObject, value);
2776 } else
2777 success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
2778 };
2779
2780#if ENABLE(SAMPLING_FLAGS)
2781 SamplingFlags::start();
2782#endif
2783
2784 for (size_t i = 0; i < scripts.size(); i++) {
2785 JSInternalPromise* promise = nullptr;
2786 bool isModule = module || scripts[i].scriptType == Script::ScriptType::Module;
2787 if (scripts[i].codeSource == Script::CodeSource::File) {
2788 fileName = scripts[i].argument;
2789 if (scripts[i].strictMode == Script::StrictMode::Strict)
2790 scriptBuffer.append("\"use strict\";\n", strlen("\"use strict\";\n"));
2791
2792 if (isModule)
2793 promise = loadAndEvaluateModule(globalObject->globalExec(), fileName);
2794 else {
2795 if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer))
2796 return false; // fail early so we can catch missing files
2797 }
2798 } else {
2799 size_t commandLineLength = strlen(scripts[i].argument);
2800 scriptBuffer.resize(commandLineLength);
2801 std::copy(scripts[i].argument, scripts[i].argument + commandLineLength, scriptBuffer.begin());
2802 fileName = ASCIILiteral("[Command Line]");
2803 }
2804
2805 bool isLastFile = i == scripts.size() - 1;
2806 if (isModule) {
2807 if (!promise)
2808 promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
2809 scope.clearException();
2810
2811 JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
2812 checkException(isLastFile, false, exec->argument(0));
2813 return JSValue::encode(jsUndefined());
2814 });
2815
2816 JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
2817 checkException(isLastFile, true, exec->argument(0));
2818 return JSValue::encode(jsUndefined());
2819 });
2820
2821 promise->then(globalObject->globalExec(), fulfillHandler, rejectHandler);
2822 vm.drainMicrotasks();
2823 } else {
2824 NakedPtr<Exception> evaluationException;
2825 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, fileName), JSValue(), evaluationException);
2826 ASSERT(!scope.exception());
2827 if (evaluationException)
2828 returnValue = evaluationException->value();
2829 checkException(isLastFile, evaluationException, returnValue);
2830 }
2831
2832 scriptBuffer.clear();
2833 scope.clearException();
2834 }
2835
2836#if ENABLE(REGEXP_TRACING)
2837 vm.dumpRegExpTrace();
2838#endif
2839 return success;
2840}
2841
2842#define RUNNING_FROM_XCODE 0
2843
2844static void runInteractive(GlobalObject* globalObject)
2845{
2846 VM& vm = globalObject->vm();
2847 auto scope = DECLARE_CATCH_SCOPE(vm);
2848
2849 String interpreterName(ASCIILiteral("Interpreter"));
2850
2851 bool shouldQuit = false;
2852 while (!shouldQuit) {
2853#if HAVE(READLINE) && !RUNNING_FROM_XCODE
2854 ParserError error;
2855 String source;
2856 do {
2857 error = ParserError();
2858 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
2859 shouldQuit = !line;
2860 if (!line)
2861 break;
2862 source = source + line;
2863 source = source + '\n';
2864 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
2865 if (!line[0]) {
2866 free(line);
2867 break;
2868 }
2869 add_history(line);
2870 free(line);
2871 } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable);
2872
2873 if (error.isValid()) {
2874 printf("%s:%d\n", error.message().utf8().data(), error.line());
2875 continue;
2876 }
2877
2878
2879 NakedPtr<Exception> evaluationException;
2880 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), evaluationException);
2881#else
2882 printf("%s", interactivePrompt);
2883 Vector<char, 256> line;
2884 int c;
2885 while ((c = getchar()) != EOF) {
2886 // FIXME: Should we also break on \r?
2887 if (c == '\n')
2888 break;
2889 line.append(c);
2890 }
2891 if (line.isEmpty())
2892 break;
2893
2894 NakedPtr<Exception> evaluationException;
2895 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, interpreterName), JSValue(), evaluationException);
2896#endif
2897 if (evaluationException)
2898 printf("Exception: %s\n", evaluationException->value().toWTFString(globalObject->globalExec()).utf8().data());
2899 else
2900 printf("%s\n", returnValue.toWTFString(globalObject->globalExec()).utf8().data());
2901
2902 scope.clearException();
2903 globalObject->vm().drainMicrotasks();
2904 }
2905 printf("\n");
2906}
2907
2908static NO_RETURN void printUsageStatement(bool help = false)
2909{
2910 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
2911 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
2912 fprintf(stderr, " -e Evaluate argument as script code\n");
2913 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
2914 fprintf(stderr, " -h|--help Prints this help message\n");
2915 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
2916 fprintf(stderr, " -m Execute as a module\n");
2917#if HAVE(SIGNAL_H)
2918 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
2919#endif
2920 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
2921 fprintf(stderr, " -x Output exit code before terminating\n");
2922 fprintf(stderr, "\n");
2923 fprintf(stderr, " --sample Collects and outputs sampling profiler data\n");
2924 fprintf(stderr, " --test262-async Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n");
2925 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");
2926 fprintf(stderr, " --module-file=<file> Parse and evaluate the given file as module (this option may be passed more than once)\n");
2927 fprintf(stderr, " --exception=<name> Check the last script exits with an uncaught exception with the specified name\n");
2928 fprintf(stderr, " --dumpException Dump uncaught exception text\n");
2929 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
2930 fprintf(stderr, " --dumpOptions Dumps all non-default JSC VM options before continuing\n");
2931 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
2932 fprintf(stderr, "\n");
2933
2934 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
2935}
2936
2937void CommandLine::parseArguments(int argc, char** argv)
2938{
2939 Options::initialize();
2940
2941 int i = 1;
2942 JSC::Options::DumpLevel dumpOptionsLevel = JSC::Options::DumpLevel::None;
2943 bool needToExit = false;
2944
2945 bool hasBadJSCOptions = false;
2946 for (; i < argc; ++i) {
2947 const char* arg = argv[i];
2948 if (!strcmp(arg, "-f")) {
2949 if (++i == argc)
2950 printUsageStatement();
2951 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
2952 continue;
2953 }
2954 if (!strcmp(arg, "-e")) {
2955 if (++i == argc)
2956 printUsageStatement();
2957 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::CommandLine, Script::ScriptType::Script, argv[i]));
2958 continue;
2959 }
2960 if (!strcmp(arg, "-i")) {
2961 m_interactive = true;
2962 continue;
2963 }
2964 if (!strcmp(arg, "-d")) {
2965 m_dump = true;
2966 continue;
2967 }
2968 if (!strcmp(arg, "-p")) {
2969 if (++i == argc)
2970 printUsageStatement();
2971 m_profile = true;
2972 m_profilerOutput = argv[i];
2973 continue;
2974 }
2975 if (!strcmp(arg, "-m")) {
2976 m_module = true;
2977 continue;
2978 }
2979 if (!strcmp(arg, "-s")) {
2980#if HAVE(SIGNAL_H)
2981 signal(SIGILL, _exit);
2982 signal(SIGFPE, _exit);
2983 signal(SIGBUS, _exit);
2984 signal(SIGSEGV, _exit);
2985#endif
2986 continue;
2987 }
2988 if (!strcmp(arg, "-x")) {
2989 m_exitCode = true;
2990 continue;
2991 }
2992 if (!strcmp(arg, "--")) {
2993 ++i;
2994 break;
2995 }
2996 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
2997 printUsageStatement(true);
2998
2999 if (!strcmp(arg, "--options")) {
3000 dumpOptionsLevel = JSC::Options::DumpLevel::Verbose;
3001 needToExit = true;
3002 continue;
3003 }
3004 if (!strcmp(arg, "--dumpOptions")) {
3005 dumpOptionsLevel = JSC::Options::DumpLevel::Overridden;
3006 continue;
3007 }
3008 if (!strcmp(arg, "--sample")) {
3009 JSC::Options::useSamplingProfiler() = true;
3010 JSC::Options::collectSamplingProfilerDataForJSCShell() = true;
3011 m_dumpSamplingProfilerData = true;
3012 continue;
3013 }
3014
3015 static const char* timeoutMultiplierOptStr = "--timeoutMultiplier=";
3016 static const unsigned timeoutMultiplierOptStrLength = strlen(timeoutMultiplierOptStr);
3017 if (!strncmp(arg, timeoutMultiplierOptStr, timeoutMultiplierOptStrLength)) {
3018 const char* valueStr = &arg[timeoutMultiplierOptStrLength];
3019 if (sscanf(valueStr, "%lf", &s_timeoutMultiplier) != 1)
3020 dataLog("WARNING: --timeoutMultiplier=", valueStr, " is invalid. Expects a numeric ratio.\n");
3021 continue;
3022 }
3023
3024 if (!strcmp(arg, "--test262-async")) {
3025 test262AsyncTest = true;
3026 continue;
3027 }
3028
3029 if (!strcmp(arg, "--remote-debug")) {
3030 m_enableRemoteDebugging = true;
3031 continue;
3032 }
3033
3034 static const unsigned strictFileStrLength = strlen("--strict-file=");
3035 if (!strncmp(arg, "--strict-file=", strictFileStrLength)) {
3036 m_scripts.append(Script(Script::StrictMode::Strict, Script::CodeSource::File, Script::ScriptType::Script, argv[i] + strictFileStrLength));
3037 continue;
3038 }
3039
3040 static const unsigned moduleFileStrLength = strlen("--module-file=");
3041 if (!strncmp(arg, "--module-file=", moduleFileStrLength)) {
3042 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Module, argv[i] + moduleFileStrLength));
3043 continue;
3044 }
3045
3046 if (!strcmp(arg, "--dumpException")) {
3047 m_alwaysDumpUncaughtException = true;
3048 continue;
3049 }
3050
3051 static const unsigned exceptionStrLength = strlen("--exception=");
3052 if (!strncmp(arg, "--exception=", exceptionStrLength)) {
3053 m_uncaughtExceptionName = String(arg + exceptionStrLength);
3054 continue;
3055 }
3056
3057 // See if the -- option is a JSC VM option.
3058 if (strstr(arg, "--") == arg) {
3059 if (!JSC::Options::setOption(&arg[2])) {
3060 hasBadJSCOptions = true;
3061 dataLog("ERROR: invalid option: ", arg, "\n");
3062 }
3063 continue;
3064 }
3065
3066 // This arg is not recognized by the VM nor by jsc. Pass it on to the
3067 // script.
3068 m_scripts.append(Script(Script::StrictMode::Sloppy, Script::CodeSource::File, Script::ScriptType::Script, argv[i]));
3069 }
3070
3071 if (hasBadJSCOptions && JSC::Options::validateOptions())
3072 CRASH();
3073
3074 if (m_scripts.isEmpty())
3075 m_interactive = true;
3076
3077 for (; i < argc; ++i)
3078 m_arguments.append(argv[i]);
3079
3080 if (dumpOptionsLevel != JSC::Options::DumpLevel::None) {
3081 const char* optionsTitle = (dumpOptionsLevel == JSC::Options::DumpLevel::Overridden)
3082 ? "Modified JSC runtime options:"
3083 : "All JSC runtime options:";
3084 JSC::Options::dumpAllOptions(stderr, dumpOptionsLevel, optionsTitle);
3085 }
3086 JSC::Options::ensureOptionsAreCoherent();
3087 if (needToExit)
3088 jscExit(EXIT_SUCCESS);
3089}
3090
3091// We make this function no inline so that globalObject won't be on the stack if we do a GC in jscmain.
3092static int NEVER_INLINE runJSC(VM* vm, CommandLine options)
3093{
3094 JSLockHolder locker(vm);
3095
3096 int result;
3097 if (options.m_profile && !vm->m_perBytecodeProfiler)
3098 vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
3099
3100 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
3101 globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
3102 bool success = runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
3103 if (options.m_interactive && success)
3104 runInteractive(globalObject);
3105
3106 vm->drainMicrotasks();
3107 result = success && (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
3108
3109 if (options.m_exitCode)
3110 printf("jsc exiting %d\n", result);
3111
3112 if (options.m_profile) {
3113 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
3114 fprintf(stderr, "could not save profiler output.\n");
3115 }
3116
3117#if ENABLE(JIT)
3118 if (Options::useExceptionFuzz())
3119 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
3120 bool fireAtEnabled =
3121 Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
3122 if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
3123 printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
3124 if (Options::useOSRExitFuzz()) {
3125 printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks());
3126 printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks());
3127 }
3128
3129 auto compileTimeStats = JIT::compileTimeStats();
3130 Vector<CString> compileTimeKeys;
3131 for (auto& entry : compileTimeStats)
3132 compileTimeKeys.append(entry.key);
3133 std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
3134 for (CString key : compileTimeKeys)
3135 printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
3136#endif
3137
3138 return result;
3139}
3140
3141int jscmain(int argc, char** argv)
3142{
3143 // Note that the options parsing can affect VM creation, and thus
3144 // comes first.
3145 CommandLine options(argc, argv);
3146
3147 // Initialize JSC before getting VM.
3148 WTF::initializeMainThread();
3149 JSC::initializeThreading();
3150 startTimeoutThreadIfNeeded();
3151
3152 VM* vm = &VM::create(LargeHeap).leakRef();
3153 int result;
3154 result = runJSC(vm, options);
3155
3156 if (Options::gcAtEnd()) {
3157 // We need to hold the API lock to do a GC.
3158 JSLockHolder locker(vm);
3159 vm->heap.collectAllGarbage();
3160 }
3161
3162 if (options.m_dumpSamplingProfilerData) {
3163#if ENABLE(SAMPLING_PROFILER)
3164 JSLockHolder locker(vm);
3165 vm->samplingProfiler()->reportTopFunctions();
3166 vm->samplingProfiler()->reportTopBytecodes();
3167#else
3168 dataLog("Sampling profiler is not enabled on this platform\n");
3169#endif
3170 }
3171
3172 printSuperSamplerState();
3173
3174 return result;
3175}
3176
3177#if OS(WINDOWS)
3178extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
3179{
3180 return main(argc, const_cast<char**>(argv));
3181}
3182#endif
Note: See TracBrowser for help on using the repository browser.