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

Last change on this file since 205670 was 205670, checked in by Chris Dumez, 9 years ago

Align proto getter / setter behavior with other browsers
https://bugs.webkit.org/show_bug.cgi?id=161455

Reviewed by Saam Barati.

Source/JavaScriptCore:

Drop allowsAccessFrom from the methodTable and delegate cross-origin
checking to the DOM bindings for SetPrototypeOf / GetPrototypeOf.
This is more consistent with other operations (e.g. GetOwnProperty).

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

(JSC::globalFuncProtoGetter):
(JSC::globalFuncProtoSetter):
(JSC::globalFuncBuiltinLog): Deleted.

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

(JSC::JSObject::setPrototypeWithCycleCheck):
Remove check added in r197648. This check was added to match
the latest EcmaScript spec:

This check allowed for Prototype chain cycles if the prototype
chain includes objects that do not use the ordinary object definitions
for GetPrototypeOf and SetPrototypeOf.
The issue is that the rest of our code base does not properly handle
such cycles and we can end up in infinite loops. This became obvious
because this patch updates Window / Location so that they no longer
use the default GetPrototypeOf / SetPrototypeOf. If I do not
remove this check, I get an infinite loop in
Structure::anyObjectInChainMayInterceptIndexedAccesses(), which is
called from JSObject::setPrototypeDirect(), when running the following
layout test:

  • html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html

I filed https://bugs.webkit.org/show_bug.cgi?id=161534 to track this
issue.

  • runtime/JSObject.h:

(JSC::JSObject::getArrayLength): Deleted.

  • runtime/JSProxy.cpp:

(JSC::JSProxy::setPrototype):
(JSC::JSProxy::getPrototype):

  • runtime/JSProxy.h:
  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorGetPrototypeOf):
(JSC::objectConstructorSetPrototypeOf):
(JSC::objectConstructorGetOwnPropertyDescriptor): Deleted.
(JSC::objectConstructorGetOwnPropertyDescriptors): Deleted.

  • runtime/ObjectConstructor.h:
  • runtime/ReflectObject.cpp:

(JSC::reflectObjectGetPrototypeOf):
(JSC::reflectObjectSetPrototypeOf):

Source/WebCore:

Align cross-origin proto getter / setter behavior with other
browsers and the specification:

SetPrototypeOf should throw a TypeError:

GetPrototypeOf should return null cross-origin:

Test: js/dom/setPrototypeOf-location-window.html

  • bindings/js/JSDOMWindowBase.cpp:

(WebCore::JSDOMWindowBase::JSDOMWindowBase): Deleted.

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::setPrototype):
(WebCore::JSDOMWindow::getPrototype):
(WebCore::JSDOMWindow::preventExtensions):

  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::setPrototype):
(WebCore::JSLocation::getPrototype):

  • bindings/js/JSWorkerGlobalScopeBase.cpp:

(WebCore::JSWorkerGlobalScopeBase::supportsRichSourceInfo): Deleted.

  • bindings/js/JSWorkerGlobalScopeBase.h:
  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateHeader):

  • bindings/scripts/IDLAttributes.txt:
  • page/DOMWindow.idl:
  • page/Location.idl:

LayoutTests:

Add layout test coverage and update a few existing test to reflect
behavior change.

  • fast/dom/Window/script-tests/window-custom-prototype.js: Removed.
  • fast/dom/Window/window-custom-prototype-crash-expected.txt:
  • fast/dom/Window/window-custom-prototype-expected.txt: Removed.
  • fast/dom/Window/window-custom-prototype.html: Removed.
  • http/tests/security/cross-frame-access-object-getPrototypeOf-expected.txt:
  • http/tests/security/cross-frame-access-object-getPrototypeOf.html:
  • http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt:
  • http/tests/security/cross-frame-access-object-setPrototypeOf.html:
  • http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-htmlelelment-with-iframe-proto.html:
  • http/tests/security/xss-DENIED-method-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-method-with-iframe-proto.html:
  • http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-non-shadowable-propterty-with-iframe-proto.html:
  • http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto-expected.txt:
  • http/tests/security/xss-DENIED-regular-propterty-with-iframe-proto.html:
  • js/dom/setPrototypeOf-location-window-expected.txt: Added.
  • js/dom/setPrototypeOf-location-window.html: Added.
  • 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 = { &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.