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

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

Remove CopiedSpace and use MarkedSpace instead
https://bugs.webkit.org/show_bug.cgi?id=159658

Reviewed by Keith Miller.

This removes the final client of CopiedSpace, the overrides array of DirectArguments. That
is a simple change.

Then this stubs out some remaining internal debugging code that referenced CopiedSpace in
JSDollarVM and HeapVerifier. I filed FIXMEs to restore that debugging functionality.

The rest of this patch is deleting CopiedSpace.

  • API/JSObjectRef.cpp:
  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • dfg/DFGOperations.cpp:
  • heap/ConservativeRoots.cpp:

(JSC::ConservativeRoots::genericAddPointer):

  • heap/CopiedAllocator.h: Removed.
  • heap/CopiedBlock.cpp: Removed.
  • heap/CopiedBlock.h: Removed.
  • heap/CopiedBlockInlines.h: Removed.
  • heap/CopiedSpace.cpp: Removed.
  • heap/CopiedSpace.h: Removed.
  • heap/CopiedSpaceInlines.h: Removed.
  • heap/CopyBarrier.h: Removed.
  • heap/CopyToken.h: Removed.
  • heap/CopyVisitor.cpp: Removed.
  • heap/CopyVisitor.h: Removed.
  • heap/CopyVisitorInlines.h: Removed.
  • heap/CopyWorkList.h: Removed.
  • heap/Heap.cpp:

(JSC::Heap::Heap):
(JSC::Heap::isPagedOut):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::size):
(JSC::Heap::capacity):
(JSC::Heap::collectImpl):
(JSC::Heap::stopAllocation):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::copyBackingStores): Deleted.
(JSC::Heap::threadBytesCopied): Deleted.

  • heap/Heap.h:

(JSC::Heap::objectSpace):
(JSC::Heap::allocatorForAuxiliaryData):
(JSC::Heap::storageSpace): Deleted.
(JSC::Heap::storageAllocator): Deleted.

  • heap/HeapCellInlines.h:
  • heap/HeapInlines.h:

(JSC::Heap::tryAllocateStorage): Deleted.
(JSC::Heap::tryReallocateStorage): Deleted.

  • heap/HeapVerifier.cpp:

(JSC::HeapVerifier::verifyButterflyIsInStorageSpace):
(JSC::HeapVerifier::reportObject):
(JSC::getButterflyDetails): Deleted.

  • heap/SlotVisitor.cpp:

(JSC::SlotVisitor::copyLater): Deleted.

  • heap/SlotVisitor.h:
  • jit/AssemblyHelpers.h:
  • jit/JITOpcodes.cpp:
  • jsc.cpp:
  • runtime/ArrayConstructor.cpp:
  • runtime/ArrayPrototype.cpp:
  • runtime/Butterfly.h:
  • runtime/ButterflyInlines.h:

(JSC::Butterfly::createUninitializedDuringCollection): Deleted.

  • runtime/ClassInfo.h:
  • runtime/DirectArguments.cpp:

(JSC::DirectArguments::visitChildren):
(JSC::DirectArguments::overrideThings):
(JSC::DirectArguments::copyBackingStore): Deleted.

  • runtime/DirectArguments.h:
  • runtime/JSArray.cpp:
  • runtime/JSCell.cpp:

(JSC::JSCell::copyBackingStore): Deleted.

  • runtime/JSCell.h:
  • runtime/JSLexicalEnvironment.h:
  • runtime/JSObject.cpp:
  • runtime/JSTypedArrays.cpp:
  • runtime/LiteralParser.cpp:
  • runtime/ObjectConstructor.cpp:
  • runtime/RegExpObject.cpp:
  • runtime/StringPrototype.cpp:
  • runtime/WeakMapData.cpp:
  • tools/JSDollarVMPrototype.cpp:

(JSC::JSDollarVMPrototype::isInStorageSpace):

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