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

Last change on this file since 210522 was 210522, checked in by Yusuke Suzuki, 8 years ago

[JSC] Prototype dynamic-import
https://bugs.webkit.org/show_bug.cgi?id=165724

Reviewed by Saam Barati.

JSTests:

  • stress/import-basic.js: Added.

(async.async.load):
(async):
(catch):

  • stress/import-from-eval.js: Added.

(async):
(catch):

  • stress/import-syntax.js: Added.

(testSyntaxError):

  • stress/import-tests/cocoa.js: Added.

(export.Cocoa):
(export.hello):

  • stress/import-tests/multiple.js: Added.

(export.result):

  • stress/import-tests/multiple2.js: Added.

(export.ok):

  • stress/import-tests/should.js: Added.

(export.shouldBe):
(export.shouldThrow):

  • stress/modules-syntax-error.js:

Source/JavaScriptCore:

In this patch, we implement stage3 dynamic-import proposal[1].
This patch adds a new special operator import. And by using it, we can import
the module dynamically from modules and scripts. Before this feature, the module
is always imported statically and before executing the modules, importing the modules
needs to be done. And especially, the module can only be imported from the module.
So the classic script cannot import and use the modules. This dynamic-import relaxes
the above restrictions.

The typical dynamic-import form is the following.

import("...").then(function (namespace) { ... });

You can pass any AssignmentExpression for the import operator. So you can determine
the importing modules dynamically.

import(value).then(function (namespace) { ... });

And previously the module import declaration is only allowed in the top level statements.
But this import operator is just an expression. So you can use it in the function.
And you can use it conditionally.

async function go(cond)
{

if (cond)

return import("...");

return undefined;

}
await go(true);

Currently, this patch just implements this feature only for the JSC shell.
JSC module loader requires a new hook, importModule. And the JSC shell implements
this hook. So, for now, this dynamic-import is not available in the browser side.
If you write this import call, it always returns the rejected promise.

import is implemented like a special operator similar to super.
This is because import is context-sensitive. If you call the import, the module
key resolution is done based on the caller's running context.

For example, if you are running the script which filename is "./ok/hello.js", the module
key for the callimport("./resource/syntax.js") becomes "./ok/resource/syntax.js".
But if you write the completely same import form in the script "./error/hello.js", the
key becomes "./error/resource/syntax.js". So exposing this feature as the import
function is misleading: this function becomes caller's context-sensitive. That's why
dynamic-import is specified as a special operator.

To resolve the module key, we need the caller's context information like the filename of
the caller. This is provided by the SourceOrigin implemented in r210149.
In the JSC shell implementation, this SourceOrigin holds the filename of the caller. So
based on this implementation, the module loader resolve the module key.
In the near future, we will extend this SourceOrigin to hold more information needed for
the browser-side import implementation.

[1]: https://tc39.github.io/proposal-dynamic-import/

  • builtins/ModuleLoaderPrototype.js:

(importModule):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitGetTemplateObject):
(JSC::BytecodeGenerator::emitGetGlobalPrivate):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::ImportNode::emitBytecode):

  • jsc.cpp:

(absolutePath):
(GlobalObject::moduleLoaderImportModule):
(functionRun):
(functionLoad):
(functionCheckSyntax):
(runWithScripts):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createImportExpr):

  • parser/NodeConstructors.h:

(JSC::ImportNode::ImportNode):

  • parser/Nodes.h:

(JSC::ExpressionNode::isImportNode):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseMemberExpression):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createImportExpr):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSGlobalObject.h:
  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncImportModule):

  • runtime/JSGlobalObjectFunctions.h:
  • runtime/JSModuleLoader.cpp:

(JSC::JSModuleLoader::importModule):
(JSC::JSModuleLoader::getModuleNamespaceObject):

  • runtime/JSModuleLoader.h:
  • runtime/ModuleLoaderPrototype.cpp:

(JSC::moduleLoaderPrototypeGetModuleNamespaceObject):

Source/WebCore:

We do not set a handler for import for now.
So dynamic import feature is only enabled in the JSC shell right now.

  • bindings/js/JSDOMWindowBase.cpp:
  • bindings/js/JSWorkerGlobalScopeBase.cpp:

LayoutTests:

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