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

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

Implement calls to JavaScript functions in WebAssembly
https://bugs.webkit.org/show_bug.cgi?id=149093

Patch by Sukolsak Sakshuwong <Sukolsak Sakshuwong> on 2015-09-15
Reviewed by Filip Pizlo.

This patch implements calls to JavaScript functions in WebAssembly.
WebAssembly functions can only call JavaScript functions that are
imported to their module via an object that is passed into
loadWebAssembly(). References to JavaScript functions are resolved at
the module's load time, just like asm.js.

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionLoadWebAssembly):

  • tests/stress/wasm-calls.js:
  • tests/stress/wasm/calls.wasm:
  • wasm/JSWASMModule.cpp:

(JSC::JSWASMModule::visitChildren):

  • wasm/JSWASMModule.h:

(JSC::JSWASMModule::importedFunctions):

  • wasm/WASMFunctionCompiler.h:

(JSC::WASMFunctionCompiler::buildCallImport):

  • wasm/WASMFunctionParser.cpp:

(JSC::WASMFunctionParser::parseExpressionI32):
(JSC::WASMFunctionParser::parseExpressionF64):
(JSC::WASMFunctionParser::parseCallImport):

  • wasm/WASMFunctionParser.h:
  • wasm/WASMFunctionSyntaxChecker.h:

(JSC::WASMFunctionSyntaxChecker::buildCallInternal):
(JSC::WASMFunctionSyntaxChecker::buildCallImport):
(JSC::WASMFunctionSyntaxChecker::updateTempStackHeightForCall):

  • wasm/WASMModuleParser.cpp:

(JSC::WASMModuleParser::WASMModuleParser):
(JSC::WASMModuleParser::parse):
(JSC::WASMModuleParser::parseModule):
(JSC::WASMModuleParser::parseFunctionImportSection):
(JSC::WASMModuleParser::getImportedValue):
(JSC::parseWebAssembly):

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