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

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

Intl.Collator uses POSIX locale (detected by js/intl-collator.html on iOS Simulator)
https://bugs.webkit.org/show_bug.cgi?id=152448

Patch by Andy VanWagoner <[email protected]> on 2016-02-27
Reviewed by Darin Adler.

Source/JavaScriptCore:

Add defaultLanguage to the globalObjectMethodTable and use it for the
default locale in Intl object initializations. Fall back to ICU default
locale only if the defaultLanguage function is null, or returns an
empty string.

  • jsc.cpp:
  • runtime/IntlCollator.cpp:

(JSC::IntlCollator::initializeCollator):

  • runtime/IntlDateTimeFormat.cpp:

(JSC::IntlDateTimeFormat::initializeDateTimeFormat):

  • runtime/IntlNumberFormat.cpp:

(JSC::IntlNumberFormat::initializeNumberFormat):

  • runtime/IntlObject.cpp:

(JSC::defaultLocale):
(JSC::lookupMatcher):
(JSC::bestFitMatcher):
(JSC::resolveLocale):

  • runtime/IntlObject.h:
  • runtime/JSGlobalObject.cpp:
  • runtime/JSGlobalObject.h:
  • runtime/StringPrototype.cpp:

(JSC::toLocaleCase):

Source/WebCore:

Pass defaultLanguage from Language.h to the globalObjectMethodTable to
ensure Intl objects can be initialized with the correct default locale.

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

LayoutTests:

Add tests for default locale in test runner to be en-US.

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